ASM.E provides functions for allocating machine code from a 
  sequence of assembly language commands.
Send questions or comments to: Pete Eberlein <xseal@harborside.com>

new in this release:
    SSE4 instructions
	
new in previous releases:
    SSSE3 instructions
    SSE3 instructions
    Better handling of MMX/SSE instruction operands		
    SSE instructions
    Conditional move instructions
    Floating point compare instructions setting integer flags
    Conditional floating point move instructions
    MMX instructions, 3DNow!, RDTSC
    SETcc instructions
    floating point instructions
    internal references, @

-------------------------------------------------------------
--- quick ref
-------------------------------------------------------------
function get_asm(sequence text)
  returns integer pointer to allocated machine code
  note: you must deallocate this pointer yourself using free()

function get_param(sequence name)
  returns the offset into a machine code sequence of a parameter,
  or 0 if no such parameter exists (no parameter length indication is given)

procedure resolve_param(sequence name, object data)
  resolve_param sets that data located by name with the data.

procedure asm_output(output_file, style)
  Sets up the file for output when get_asm is called.  style
  determines how the output is formatted.  output_file may be
  a sequence naming the file or an atom of a file already opened.
  Allowed styles are:
    1 - machine codes with commented source and line numbers
    2 - machine codes with commented source only
    3 - machine codes only, no commented source
----------------------------------------------------------------------------


code example:
---- code begins ----

include asm.e

constant mach_proc = get_asm(
    "push eax " &
    "mov eax, dummy " &
    "add eax, 1000 " &
    "pop eax " &
    "ret")
constant dummy = mach_proc + get_param("dummy")
poke(dummy, int_to_bytes(100577))
call(mach_proc)
free(mach_proc)

---- code ends ----




Structures and Unions are available:
"    Struc PosType                      " &
"        Row     dw  ?                  " &
"        Col     dw  ?                  " &
"    Ends PosType                       " &
"                                       " &
"    Union PosValType                   " &
"        Pos     PosType     ?          " &
"        Val     dd          ?          " &
"    Ends PosValType                    " &
"    mov eax,[ebx + PosValType.Pos.Col] " &
"    mov eax,[(PosType ebx).Col]        " &
"    Dummy PosType                      "

Labels may be followed by a colon ':', but the colon is not neccessary.

    label1: 
        lodsd         ; read a dword from [esi], inc esi
        test eax,eax  ; test eax for zero
        jnz label1    ; jump to label1 if zero flag is not set

Data may be declared using DB,DW,DD instructions or by using a struc.
Unions are initialized to the first element's initializers only.
Declared data may now be referenced in an effective addresses.

    mov eax, 1000
    mov dword ptr [@foo], eax
    jmp 0
    mov ebx, foo
    ...

A label may be used in place of an immediate value.  Calling get_param with
that label name will return the offset of the immediate data in the instruction.
You may poke your own values into that location.  Since the label does not
indicate a value, the immediate data is initialized to zeros.  The keyword
BYTE or WORD or DWORD may precede the label, indicating the size of the
value.  This is useful for instructions that vary depending on the magnitude
of the immediate value, or to make sure that you know what size the data will
be when you poke it in.
Example:
    #81,#C2,#E8,#03,#00,#00,--add edx, 1000
    #83,#C2,#64,            --add edx, 100
    #81,#C2,#00,#00,#00,#00,--add edx, dum2
    #83,#C2,#00,            --add edx, byte dum3
Parameters may also be used in effective addresses for an immediate
displacement.  The size indicator may also be used.
Example:
    #89,#02,                --mov [edx], eax
    #89,#42,#64,            --mov [edx+100], eax
    #89,#82,#E8,#03,#00,#00,--mov [edx+1000], eax
    #89,#82,#00,#00,#00,#00,--mov [edx+dum4], eax
    #89,#42,#00,            --mov [edx+byte dum5], eax
You can also reference a single parameter in your code using the @ operator.
This makes self-modifying code very easy to do.
    mov eax, happy     ; get happy
    inc eax            ; increase happiness
    mov [@happy], eax  ; save happiness for next time around



Instructions supported:

Data transfer:
    MOV, PUSH, POP, XCHG, IN, OUT, XLAT, LEA, LDS, LES
    PUSHA, POPA, PUSHF, POPF, SAHF, LAHF

Conditional move instructions: (use only with >=P6)
    CMOVO, CMOVNO,CMOVB, CMOVC, CMOVNAE,CMOVNB,CMOVNC,CMOVAE
    CMOVE, CMOVZ, CMOVNE, CMOVNZ, CMOVBE, CMOVNA, CMOVNBE
    CMOVA, CMOVS, CMOVNS, CMOVP, CMOVPE, CMOVNP, CMOVPO
    CMOVL, CMOVNGE, CMOVNL, CMOVGE, CMOVLE, CMOVNLE, CMOVG

Arithmetic:
    ADD, ADC, AAA, DAA, SUB, SBB, DEC, NEG, CMP, AAS, DAS,
    MUL, IMUL, AAM, DIV, IDIV, AAD, CBW, CWD, LEA,
    SETcc (cc=A,AE,B,BE,C,E,G,GE,L,LE,NA,NAE,NB,NBE,NC,NE,NG,
    NGE,NL,NLE,NO,NP,NS,NZ,O,P,PE,PO,S,Z)

Logic:
    NOT, SHL, SAL, SHR, SAR, ROL, ROR, RCL, RCR,
    AND, TEST, OR, XOR, SHRD, SHLD

Processor control:
    CLC, STC, CMC, NOP, CLD, STD, CLI, STI, 
    HLT, WAIT, LOCK
    INT0, INT, RET, RETF, IRET

Jumps and looping:
    Jcc (cc=A,AE,B,BE,C,E,G,GE,L,LE,NA,NAE,NB,NBE,NC,NE,NG,
    NGE,NL,NLE,NO,NP,NS,NZ,O,P,PE,PO,S,Z)
    LOOPNE, LOOPE, LOOP, JCXZ, JMP SHORT, JMP NEAR, CALL NEAR, JMP FAR

String operations:
    INSB, INSW, INSD, OUTSB, OUTSW, OUTSD
    MOVSB, MOVSW, MOVSD, CMPSB, CMPSW, CMPSD
    STOSB, STOSW, STOSD, LODSB, LODSW, LODSD
    SCASB, SCASW, SCASD

Instruction prefixes:
    LOCK, REPNE, REPNZ, REP, REPE, REPZ
    SEG_ES, SEG_CS, SEG_SS, SEG_CS, SEG_FS, SEG_GS

Misc:
    CPUID, RDTSC



FPU Instructions supported:

Data transfer:
    FLD, FILD, FBLD, FST, FIST, FSTP, FISTP, FBSTP, FXCH

Conditional move instructions: (use only with >=P6)
    FCMOVB, FCMOVC, FCMOVNB, FCMOVNC, FCMOVAE, FCMOVE, FCMOVZ
    FCMOVNE, FCMOVNZ, FCMOVBE, FCMOVNA, FCMOVNBE, FCMOVA
    FCMOVU, FCMOVNU 

Comparison:
    FCOM, FICOM, FCOMP, FICOMP, FCOMPP, FTST, FXAM

Comparison setting integer flags: (use only with >=P6)
    FCOMI, FCOMIP, FUCOMI, FUCOMIP

Arithmetic:
    FADD, ADDP, FSUB, FSUBR, FSUBP, FSUBRP, FMUL, FMULP, FDIV, FDIVR,
    FDIVP, FDIVRP, FSQRT, FSCALE, FPREM, FRNDINT, FXTRACT, FABS, FCHS

Transcendental:
    FPTAN, FPATAN, F2XM1, FYL2X, FYL2XP1

Constants:
    FLDZ, FLD1, FLDPI, FLDL2T, FLDL2E, FLDLG2, FLDLN2

Processor Control:
    FINIT, FENI, FDISI, FLDCW, FSTCW, FSTSW, FCLEX, FSTENV, FLDENV,
    FSAVE, FRSTOR, FINCSTP, FDECSTP, FFREE, FNOP, FWAIT



MMX instructions supported:
    EMMS, MOVD, MOVQ, PACKSSDW, PACKSSWB, PACKUSWB, PADDB, PADDD, PADDSB,
    PADDSW, PADDUSB, PADDUSW, PADDW, PAND, PANDN, PCMPEQB, PCMPEQD,
    PCMPEQW, PCMPGTB, PCMPGTD, PCMPGTW, PMADDWD, PMULHW, PMULLW, POR, 
    PSLLD, PSLLQ, PSLLW, PSRAD, PSRAW, PSRLD, PSRLQ, PSRLW, PSUBB, PSUBD, 
    PSUBSB, PSUBSW, PSUBUSB, PSUBUSW, PSUBW, PUNPCKHBW, PUNPCKHDQ, 
    PUNPCKLBW, PUNPCKLDQ, PUNPCKLBW, PXOR


3DNow! instructions supported:
    FEMMS, PAVGUSB, PFADD, PFSUB, PFSUBR, PFACC, PFMUL, PFCMPGE, PFCMPGT,
    PFCMPEQ, PFMIN, PFMAX, PI2FD, PF2ID, PFRCP, PFSQRT, PFRCPIT1, PFRSQIT1,
    PFRCPIT2, PFMULHRW, PREFETCH, PREFETCHW



SETcc/Jcc Flag Interpretations

cc            Flags Tested             Meaning

A/NBE         (CF or ZF) = 0           above/not below nor equal
AE/NB         CF = 0                   above or equal/not below
B/NAE         CF = 1                   below/not above nor equal
BE/NA         (CF or ZF) = 1           below or equal/not above  
C             CF = 1                   carry
E/Z           ZF = 1                   equal/zero
NC            CF = 0                   not carry
NE/NZ         ZF = 0                   not equal/not zero
NP/PO         PF = 0                   not parity/parity odd
P/PE          PF = 1                   parity/parity even
G/NLE         ((SF xor OF) or ZF) = 0  greater/not less nor equal
GE/NL         (SF xor OF) = 0          greater or equal/not less
L/NGE         (SF xor OF) = 1          less/not greater nor equal
LE/NG         ((SF xor OF) or ZF) = 1  less or equal/not greater
NO            OF = 0                   not overflow
NS            SF = 0                   not sign (positive, including 0)
O             OF = 1                   overflow
S             SF = 1                   sign (negative)



-----------------------------------------------------------------------------
ASM32 Instruction Reference for Euphoria Programmers
-----------------------------------------------------------------------------
Assembly        Euphoria                        Meaning
--------        --------                        -------
MOV a, b        a=b                             move b to a
PUSH a          esp=esp-4  poke4(esp,a)         store a value on the stack (lifo)
POP a           a=peek4u(esp)  esp=esp + 4      get a value from the stack
XCHG a, b       temp=a  a=b  b=temp             exchange
ADD a, b        a=a+b                           add b to a
ADC a, b        a=a+b+cf                        add w/ carry bit
SUB a, b        a=a-b                           subtract b from a
SBB a, b        a=a-b-cf                        subtract w/ borrow bit
DEC a           a=a-1                           decrement
NEG a           a=-a                            negate
MUL a           ax=al*a --or-- edx:eax=eax*a    multiply
IMUL a          ax=al*a --or-- edx:eax=eax*a    signed multiply
DIV a           
NOT a           a=not_bits(a)                   invert bits
SHL a, b        a=a*power(2,b)                  shift left
SAL a, b        a=a*power(2,b)                  shift arithmetic left
SHR a, b        a=floor(a/power(2,b))           shift right
SAR a, b        a=floor(a/power(2,b))           shift arithmetic right

MOVSB           poke(edi, peek(esi))            move (string) byte
                edi = edi + 1                   (like mem_copy)
                esi = esi + 1

MOVSW           poke(edi, peek({esi,2}))        move (string) word
                edi = edi + 2
                esi = esi + 2

MOVSD           poke4(edi, peek4u(esi))         move (string) double-word
                edi = edi + 4
                esi = esi + 4

STOSB           poke(edi, al)                   store (string) byte
                edi = edi + 1

STOSW           poke(edi, ax)                   store (string) word
                edi = edi + 2

STOSD           poke4(edi, eax)                 store (string) double-word
                edi = edi + 4

LODSB           al = peek(esi)                  load (string) byte
                esi = esi + 1

LODSW           al = peek(esi)                  load (string) word
                ah = peek(esi+1)
                esi = esi + 2

LODSD           eax = peek4(esi)                load (string) double-word
                esi = esi + 4

REP MOVSB       poke(edi, peek({esi, ecx}))     move ecx bytes from esi to edi
                esi = esi + ecx
                edi = edi + ecx

REP MOVSD       poke4(edi, peek4({esi, ecx}))   move ecx dwords from esi to edi
                esi = esi + 4*ecx
                edi = edi + 4*ecx

REP STOSB       poke(edi, repeat(al, ecx))      store ecx bytes of al to edi
                edi = edi + ecx
etc. (REP works with any string instruction)

Conditional repetition: (for use with CMPS & SCAS)
REPE SCASB    	while (peek(edi)=al) and (ecx!=0) do
                  edi += 1
                  ecx -= 1
                end while

REPNE CMPSD    	while (peek4(esi)!=peek4(edi)) and (ecx!=0) do
                  edi += 4
                  ecx -= 1
                end while

etc.

CLD            ...                              sets string instructions to
                                                go forward
STD            ...                              sets string instructions to
                                                go backward

                
Registers and other weird stuff

First thing you should know is that the cpu is programmed using registers.  Each register is 
like an integer variable, you can change it or read it or whatever.  But in asm you don't 
declare registers - they're already there for you to use.  There are four general
registers called eax, ebx, ecx, edx. These are each 32-bits but can be used in many different
ways. The lowest 8 bits can be accessed in the byte-sized l-register (al for eax, bl for ebx,
etc.) The next 8 bits can be accessed in the byte-sized h-register (ah for eax, bh for ebx, etc.)
There are four other registers esi, edi, esp, ebp, ip which are used mainly for pointer
operations. The segment registers, cs, ds, es, fs, and gs, are used for selecting segments and
other stuff you usually don't have to worring about. 

eax - this register is used for almost everything
ebx - so's this one
ecx - this one can also be used for counting in a loop
edx - this one can be used for port operations

esi - a pointer to memory as the source in a mov operation
edi - a pointer to memory as the destination in a mov operation
esp - the stack pointer - don't mess with it!
ebp - just another pointer
ip - pointer to the current instruction being executed in the code segment 

cs - code segment
ds - data segment (or source segment for mov operations)
es - extra segment (or destination segment for mov operations)
fs - extra segment (funky segment)
gs - extra segment (groovy segment) 

Any of these registers can actually be used for whatever purpose you want, as long as they are
used in the correct context.  Changing esp is not recommended because it will piss off the cpu if
it's not restored after your machine code finishes.  Changing cs will also cause the cpu to do some
pretty weird stuff like executing instructions that aren't really programmed. 

[High and Low bytes in a register explained]
The low and high bytes are the lower 8-bits and upper 8-bits of a 16-bit register.  Clear as mud,
right? Here are some examples: 

say AX = #10FF
the high byte AH is #10, which is the same as floor(AX/#100) and the low byte AL is #FF, which is
the same as and_bits(AX,#FF) 

now say you have a low byte AL = #20 and high byte AH = #4C

AX = AH*#100 + AL
   = #4C*#100 + #20
   = #4C00 + #20
   = #4C20

But if you're dealing with 32-bit registers, the lower byte is the same, but the upper byte isn't
the upper-most anymore.  If EAX=#10FF09C2, then AH=and_bits(floor(EAX/#100),#FF) = #09. As before,
AL = and_bits(EAX,#FF). 

So, EAX = and_bits(EAX,#FFFF0000) + AH*#100 + AL 

To access the upper word in EAX, you may have to use a shift operation to move the bytes into AH
and AL.  ex. SHR EAX,16 

Note: these examples also work with the other general registers (BX,CX,DX or EBX,ECX,EDX with
BH,BL,CH,CL,DH,DL) 



[Load Effective Address - very useful]

lea x,[m]         x = m
  where m = a*s + b + c
  where a = register (index)
        s = 0,1,2,4,8
        b = register (base)
        c = integer constant

An effective address is the part of an instruction with the brackets []. It means to use at the
memory at the value between the brackets, so you can do pointer operations. 

mov al, [1000]     is like  "al = peek(1000)"  in Euphoria
mov eax, [edi]     is like  "eax = peek4u(edi)"  in Euphoria
mov [edi], eax     is like  "poke4(edi, eax)"  in Euphoria

Note: you cannot have two effective addresses in the same instruction, i.e. mov [edi], [esi] will
not work.  This is why some tutorials say you cannot directly move memory to memory. 

An effective address can be made up of the following three parts: 

  an integer offset:  [1000]
  a base register :  [eax]
  an index register:  [ebx*4]

  the integer offset can be any value in the range from -2^31 to 2^31-1.
  the base register can be any of the 8 general registers.
  the index register can be any of the 8 general registers multiplied by
    one of the following constants: 1,2,4,8

  these can be combined in a variety of ways:
    [eax + eax*4 + 100]
    [ebx + 10000]
    [ecx + edx]     -- edx*1 is implied
    [ebp*8]

    etc.

now back to lea... 

  lea eax, [eax + ebx*2 + 4]

    is about the same as

  mov eax, eax + ebx*2 + 4

    except that you can't have complex calculations like that in a mov
    instruction.  The benefits of lea are pretty obvious.

  a lea instruction can be use to multiply any register by certain small
  constants, without using any other registers.

    lea eax, [eax*2]        -- eax = eax * 2
    lea eax, [eax + eax*2]  -- eax = eax * 3
    lea eax, [eax*4]        -- eax = eax * 4
    lea eax, [eax + eax*2]  -- eax = eax * 3
    lea eax, [eax*4]        -- eax = eax * 4
    lea eax, [eax + eax*4]  -- eax = eax * 5
    lea eax, [eax*8]        -- eax = eax * 8
    lea eax, [eax + eax*8]  -- eax = eax * 9

  multiple lea commands can be used to perform more complex calculations,
  that would normally require more instructions and extra registers.  Lets
  use my mode 19 address calculation as an example:

    mov ebx, x
    mov edx, y

    lea edx, [edx + edx*4]     -- y = y + y*4
                               -- y = y*5
    lea edx, [edx*8 + #14000]  -- y = (y*5)*8 + #14000
                               -- y = y*40 + #14000
    lea edi, [ebx + edx*8]     -- a = x + (y*40 + #14000)*8
                               -- a = x + y*320 + #A0000
    lea edi, [ebx + edx*8]     -- a = x + (y*40 + #14000)*8
                               -- a = x + y*320 + #A0000

  see how it works?

for more info on asm, visit the following web sites:
http://www.sandpile.org/80x86/index.shtml
http://webster.ucr.edu/Page_asm/ArtofAssembly/ArtofAsm.html
http://www.x86.org/
http://www.ctyme.com/rbrown.htm
