2005-01-08 16:43:18 -05:00
|
|
|
! Copyright (C) 2005 Slava Pestov.
|
2005-05-07 22:39:00 -04:00
|
|
|
! See http://factor.sf.net/license.txt for BSD license.
|
2005-01-08 16:43:18 -05:00
|
|
|
IN: assembler
|
2005-12-02 02:25:44 -05:00
|
|
|
USING: arrays compiler errors generic kernel kernel-internals
|
|
|
|
lists math parser sequences words ;
|
|
|
|
|
|
|
|
! A postfix assembler for x86 and AMD64.
|
2005-01-08 16:43:18 -05:00
|
|
|
|
|
|
|
: byte? -128 127 between? ;
|
|
|
|
|
|
|
|
GENERIC: modifier ( op -- mod )
|
|
|
|
GENERIC: register ( op -- reg )
|
|
|
|
GENERIC: displacement ( op -- )
|
2005-07-20 00:50:26 -04:00
|
|
|
GENERIC: canonicalize ( op -- op )
|
|
|
|
|
2005-12-02 02:25:44 -05:00
|
|
|
#! Extended AMD64 registers return true.
|
|
|
|
GENERIC: extended? ( op -- ? )
|
|
|
|
#! 64-bit registers return true.
|
|
|
|
GENERIC: operand-64? ( op -- ? )
|
|
|
|
|
2005-07-20 00:50:26 -04:00
|
|
|
M: object canonicalize ;
|
2005-12-02 02:25:44 -05:00
|
|
|
M: object extended? drop f ;
|
|
|
|
M: object operand-64? drop cell 8 = ;
|
2005-01-08 16:43:18 -05:00
|
|
|
|
|
|
|
( Register operands -- eg, ECX )
|
|
|
|
: REGISTER:
|
|
|
|
CREATE dup define-symbol
|
2005-12-02 02:25:44 -05:00
|
|
|
dup scan-word "register" set-word-prop
|
|
|
|
scan-word "register-size" set-word-prop ; parsing
|
|
|
|
|
|
|
|
! x86 registers
|
|
|
|
REGISTER: AX 0 16
|
|
|
|
REGISTER: CX 1 16
|
|
|
|
REGISTER: DX 2 16
|
|
|
|
REGISTER: BX 3 16
|
|
|
|
REGISTER: SP 4 16
|
|
|
|
REGISTER: BP 5 16
|
|
|
|
REGISTER: SI 6 16
|
|
|
|
REGISTER: DI 7 16
|
|
|
|
|
|
|
|
REGISTER: EAX 0 32
|
|
|
|
REGISTER: ECX 1 32
|
|
|
|
REGISTER: EDX 2 32
|
|
|
|
REGISTER: EBX 3 32
|
|
|
|
REGISTER: ESP 4 32
|
|
|
|
REGISTER: EBP 5 32
|
|
|
|
REGISTER: ESI 6 32
|
|
|
|
REGISTER: EDI 7 32
|
|
|
|
|
|
|
|
! AMD64 registers
|
|
|
|
REGISTER: RAX 0 64
|
|
|
|
REGISTER: RCX 1 64
|
|
|
|
REGISTER: RDX 2 64
|
|
|
|
REGISTER: RBX 3 64
|
|
|
|
REGISTER: RSP 4 64
|
|
|
|
REGISTER: RBP 5 64
|
|
|
|
REGISTER: RSI 6 64
|
|
|
|
REGISTER: RDI 7 64
|
|
|
|
|
|
|
|
REGISTER: R8 8 64
|
|
|
|
REGISTER: R9 9 64
|
|
|
|
REGISTER: R10 10 64
|
|
|
|
REGISTER: R11 11 64
|
|
|
|
REGISTER: R12 12 64
|
|
|
|
REGISTER: R13 13 64
|
|
|
|
REGISTER: R14 14 64
|
|
|
|
REGISTER: R15 15 64
|
2005-01-08 16:43:18 -05:00
|
|
|
|
2005-03-05 14:45:23 -05:00
|
|
|
PREDICATE: word register "register" word-prop ;
|
2005-01-08 16:43:18 -05:00
|
|
|
|
2005-12-02 02:25:44 -05:00
|
|
|
PREDICATE: register register-32 "register-size" word-prop 32 = ;
|
|
|
|
PREDICATE: register register-64 "register-size" word-prop 64 = ;
|
|
|
|
|
2005-01-08 16:43:18 -05:00
|
|
|
M: register modifier drop BIN: 11 ;
|
2005-12-02 02:25:44 -05:00
|
|
|
M: register register "register" word-prop 7 bitand ;
|
2005-01-08 16:43:18 -05:00
|
|
|
M: register displacement drop ;
|
2005-12-02 02:25:44 -05:00
|
|
|
M: register extended? "register" word-prop 7 > ;
|
|
|
|
M: register operand-64? register-64? ;
|
2005-01-08 16:43:18 -05:00
|
|
|
|
2005-12-02 02:25:44 -05:00
|
|
|
( Indirect register operands -- eg, { ECX } )
|
|
|
|
PREDICATE: array indirect
|
|
|
|
dup length 1 = [ first register? ] [ drop f ] if ;
|
2005-01-08 16:43:18 -05:00
|
|
|
|
|
|
|
M: indirect modifier drop BIN: 00 ;
|
2005-12-02 02:25:44 -05:00
|
|
|
M: indirect register first register ;
|
2005-01-08 16:43:18 -05:00
|
|
|
M: indirect displacement drop ;
|
2005-12-02 02:25:44 -05:00
|
|
|
M: indirect canonicalize dup first EBP = [ drop { EBP 0 } ] when ;
|
|
|
|
M: indirect extended? register extended? ;
|
|
|
|
M: indirect operand-64? register register-64? ;
|
2005-01-08 16:43:18 -05:00
|
|
|
|
2005-12-02 02:25:44 -05:00
|
|
|
( Displaced indirect register operands -- eg, { EAX 4 } )
|
|
|
|
PREDICATE: array displaced
|
2005-07-20 00:50:26 -04:00
|
|
|
dup length 2 =
|
2005-09-24 15:21:17 -04:00
|
|
|
[ first2 integer? swap register? and ] [ drop f ] if ;
|
2005-01-08 16:43:18 -05:00
|
|
|
|
2005-05-28 20:52:23 -04:00
|
|
|
M: displaced modifier second byte? BIN: 01 BIN: 10 ? ;
|
2005-12-02 02:25:44 -05:00
|
|
|
M: displaced register first register ;
|
2005-01-08 16:43:18 -05:00
|
|
|
M: displaced displacement
|
2005-09-24 15:21:17 -04:00
|
|
|
second dup byte? [ compile-byte ] [ compile-cell ] if ;
|
2005-07-20 00:50:26 -04:00
|
|
|
M: displaced canonicalize
|
2005-12-02 02:25:44 -05:00
|
|
|
dup first EBP = not over second 0 = and
|
|
|
|
[ first 1array ] when ;
|
|
|
|
M: displaced extended? register extended? ;
|
|
|
|
M: displaced operand-64? register register-64? ;
|
2005-01-08 16:43:18 -05:00
|
|
|
|
2005-12-02 02:25:44 -05:00
|
|
|
( Displacement-only operands -- eg, { 1234 } )
|
|
|
|
PREDICATE: array disp-only
|
|
|
|
dup length 1 = [ first integer? ] [ drop f ] if ;
|
2005-01-08 16:43:18 -05:00
|
|
|
|
|
|
|
M: disp-only modifier drop BIN: 00 ;
|
|
|
|
M: disp-only register
|
2005-12-02 02:25:44 -05:00
|
|
|
#! x86 encodes displacement-only as { EBP }.
|
2005-01-08 16:43:18 -05:00
|
|
|
drop BIN: 101 ;
|
|
|
|
M: disp-only displacement
|
2005-12-02 02:25:44 -05:00
|
|
|
first compile-cell ;
|
2005-01-08 16:43:18 -05:00
|
|
|
|
|
|
|
( Utilities )
|
|
|
|
UNION: operand register indirect displaced disp-only ;
|
|
|
|
|
|
|
|
: 1-operand-short ( reg n -- )
|
|
|
|
#! Some instructions encode their single operand as part of
|
|
|
|
#! the opcode.
|
|
|
|
swap register + compile-byte ;
|
|
|
|
|
|
|
|
: 1-operand ( op reg -- )
|
2005-07-20 00:50:26 -04:00
|
|
|
>r canonicalize dup modifier 6 shift over register bitor r>
|
|
|
|
3 shift bitor compile-byte displacement ;
|
2005-01-08 16:43:18 -05:00
|
|
|
|
|
|
|
: immediate-8/32 ( dst imm code reg -- )
|
|
|
|
#! If imm is a byte, compile the opcode and the byte.
|
|
|
|
#! Otherwise, set the 32-bit operand flag in the opcode, and
|
|
|
|
#! compile the cell. The 'reg' is not really a register, but
|
|
|
|
#! a value for the 'reg' field of the mod-r/m byte.
|
|
|
|
>r over byte? [
|
|
|
|
BIN: 10 bitor compile-byte swap r> 1-operand
|
|
|
|
compile-byte
|
|
|
|
] [
|
|
|
|
compile-byte swap r> 1-operand
|
|
|
|
compile-cell
|
2005-09-24 15:21:17 -04:00
|
|
|
] if ;
|
2005-01-08 16:43:18 -05:00
|
|
|
|
|
|
|
: immediate-8 ( dst imm code reg -- )
|
|
|
|
#! The 'reg' is not really a register, but a value for the
|
|
|
|
#! 'reg' field of the mod-r/m byte.
|
|
|
|
>r compile-byte swap r> 1-operand compile-byte ;
|
|
|
|
|
|
|
|
: 2-operand ( dst src op -- )
|
|
|
|
#! Sets the opcode's direction bit. It is set if the
|
|
|
|
#! destination is a direct register operand.
|
|
|
|
pick register? [ BIN: 10 bitor swapd ] when
|
|
|
|
compile-byte register 1-operand ;
|
|
|
|
|
2005-03-15 22:23:52 -05:00
|
|
|
: from ( addr -- addr )
|
2005-01-08 16:43:18 -05:00
|
|
|
#! Relative to after next 32-bit immediate.
|
|
|
|
compiled-offset - 4 - ;
|
|
|
|
|
|
|
|
( Moving stuff )
|
|
|
|
GENERIC: PUSH ( op -- )
|
|
|
|
M: register PUSH HEX: 50 1-operand-short ;
|
|
|
|
M: integer PUSH HEX: 68 compile-byte compile-cell ;
|
|
|
|
M: operand PUSH HEX: ff compile-byte BIN: 110 1-operand ;
|
|
|
|
|
|
|
|
GENERIC: POP ( op -- )
|
|
|
|
M: register POP HEX: 58 1-operand-short ;
|
|
|
|
M: operand POP HEX: 8f compile-byte BIN: 000 1-operand ;
|
|
|
|
|
|
|
|
! MOV where the src is immediate.
|
|
|
|
GENERIC: (MOV-I) ( src dst -- )
|
|
|
|
M: register (MOV-I) HEX: b8 1-operand-short compile-cell ;
|
|
|
|
M: operand (MOV-I)
|
|
|
|
HEX: c7 compile-byte 0 1-operand compile-cell ;
|
|
|
|
|
|
|
|
GENERIC: MOV ( dst src -- )
|
|
|
|
M: integer MOV swap (MOV-I) ;
|
|
|
|
M: operand MOV HEX: 89 2-operand ;
|
|
|
|
|
|
|
|
( Control flow )
|
|
|
|
GENERIC: JMP ( op -- )
|
2005-03-15 22:23:52 -05:00
|
|
|
M: integer JMP HEX: e9 compile-byte from compile-cell ;
|
2005-01-08 16:43:18 -05:00
|
|
|
M: operand JMP HEX: ff compile-byte BIN: 100 1-operand ;
|
2005-05-07 22:39:00 -04:00
|
|
|
M: word JMP 0 JMP relative ;
|
2005-01-08 16:43:18 -05:00
|
|
|
|
|
|
|
GENERIC: CALL ( op -- )
|
2005-03-15 22:23:52 -05:00
|
|
|
M: integer CALL HEX: e8 compile-byte from compile-cell ;
|
2005-01-08 16:43:18 -05:00
|
|
|
M: operand CALL HEX: ff compile-byte BIN: 010 1-operand ;
|
2005-05-07 22:39:00 -04:00
|
|
|
M: word CALL 0 CALL relative ;
|
|
|
|
|
|
|
|
GENERIC: JUMPcc ( opcode addr -- )
|
|
|
|
M: integer JUMPcc ( opcode addr -- )
|
|
|
|
HEX: 0f compile-byte swap compile-byte from compile-cell ;
|
|
|
|
M: word JUMPcc ( opcode addr -- )
|
|
|
|
>r 0 JUMPcc r> relative ;
|
|
|
|
|
|
|
|
: JO HEX: 80 swap JUMPcc ;
|
|
|
|
: JNO HEX: 81 swap JUMPcc ;
|
|
|
|
: JB HEX: 82 swap JUMPcc ;
|
|
|
|
: JAE HEX: 83 swap JUMPcc ;
|
2005-05-09 22:34:47 -04:00
|
|
|
: JE HEX: 84 swap JUMPcc ; ! aka JZ
|
2005-05-07 22:39:00 -04:00
|
|
|
: JNE HEX: 85 swap JUMPcc ;
|
|
|
|
: JBE HEX: 86 swap JUMPcc ;
|
|
|
|
: JA HEX: 87 swap JUMPcc ;
|
|
|
|
: JS HEX: 88 swap JUMPcc ;
|
|
|
|
: JNS HEX: 89 swap JUMPcc ;
|
|
|
|
: JP HEX: 8a swap JUMPcc ;
|
|
|
|
: JNP HEX: 8b swap JUMPcc ;
|
|
|
|
: JL HEX: 8c swap JUMPcc ;
|
|
|
|
: JGE HEX: 8d swap JUMPcc ;
|
|
|
|
: JLE HEX: 8e swap JUMPcc ;
|
|
|
|
: JG HEX: 8f swap JUMPcc ;
|
2005-01-08 16:43:18 -05:00
|
|
|
|
|
|
|
: RET ( -- ) HEX: c3 compile-byte ;
|
|
|
|
|
|
|
|
( Arithmetic )
|
|
|
|
|
|
|
|
GENERIC: ADD ( dst src -- )
|
|
|
|
M: integer ADD HEX: 81 BIN: 000 immediate-8/32 ;
|
2005-05-06 19:49:07 -04:00
|
|
|
M: operand ADD OCT: 001 2-operand ;
|
2005-01-08 16:43:18 -05:00
|
|
|
|
2005-05-06 19:49:07 -04:00
|
|
|
GENERIC: OR ( dst src -- )
|
|
|
|
M: integer OR HEX: 81 BIN: 001 immediate-8/32 ;
|
|
|
|
M: operand OR OCT: 011 2-operand ;
|
|
|
|
|
|
|
|
GENERIC: ADC ( dst src -- )
|
|
|
|
M: integer ADC HEX: 81 BIN: 010 immediate-8/32 ;
|
|
|
|
M: operand ADC OCT: 021 2-operand ;
|
|
|
|
|
|
|
|
GENERIC: SBB ( dst src -- )
|
|
|
|
M: integer SBB HEX: 81 BIN: 011 immediate-8/32 ;
|
|
|
|
M: operand SBB OCT: 031 2-operand ;
|
2005-01-08 16:43:18 -05:00
|
|
|
|
2005-01-16 17:58:28 -05:00
|
|
|
GENERIC: AND ( dst src -- )
|
|
|
|
M: integer AND HEX: 81 BIN: 100 immediate-8/32 ;
|
2005-05-06 19:49:07 -04:00
|
|
|
M: operand AND OCT: 041 2-operand ;
|
|
|
|
|
|
|
|
GENERIC: SUB ( dst src -- )
|
|
|
|
M: integer SUB HEX: 81 BIN: 101 immediate-8/32 ;
|
|
|
|
M: operand SUB OCT: 051 2-operand ;
|
|
|
|
|
|
|
|
GENERIC: XOR ( dst src -- )
|
|
|
|
M: integer XOR HEX: 81 BIN: 110 immediate-8/32 ;
|
|
|
|
M: operand XOR OCT: 061 2-operand ;
|
|
|
|
|
|
|
|
GENERIC: CMP ( dst src -- )
|
|
|
|
M: integer CMP HEX: 81 BIN: 111 immediate-8/32 ;
|
|
|
|
M: operand CMP OCT: 071 2-operand ;
|
2005-01-16 17:58:28 -05:00
|
|
|
|
2005-05-07 22:39:00 -04:00
|
|
|
: NOT ( dst -- ) HEX: f7 compile-byte BIN: 010 1-operand ;
|
|
|
|
: NEG ( dst -- ) HEX: f7 compile-byte BIN: 011 1-operand ;
|
|
|
|
: MUL ( dst -- ) HEX: f7 compile-byte BIN: 100 1-operand ;
|
|
|
|
: IMUL ( src -- ) HEX: f7 compile-byte BIN: 101 1-operand ;
|
|
|
|
: DIV ( dst -- ) HEX: f7 compile-byte BIN: 110 1-operand ;
|
|
|
|
: IDIV ( src -- ) HEX: f7 compile-byte BIN: 111 1-operand ;
|
2005-01-08 16:43:18 -05:00
|
|
|
|
|
|
|
: CDQ HEX: 99 compile-byte ;
|
|
|
|
|
2005-05-09 22:34:47 -04:00
|
|
|
: ROL ( dst n -- ) HEX: c1 BIN: 000 immediate-8 ;
|
|
|
|
: ROR ( dst n -- ) HEX: c1 BIN: 001 immediate-8 ;
|
|
|
|
: RCL ( dst n -- ) HEX: c1 BIN: 010 immediate-8 ;
|
|
|
|
: RCR ( dst n -- ) HEX: c1 BIN: 011 immediate-8 ;
|
2005-05-07 22:39:00 -04:00
|
|
|
: SHL ( dst n -- ) HEX: c1 BIN: 100 immediate-8 ;
|
|
|
|
: SHR ( dst n -- ) HEX: c1 BIN: 101 immediate-8 ;
|
|
|
|
: SAR ( dst n -- ) HEX: c1 BIN: 111 immediate-8 ;
|
2005-01-08 16:43:18 -05:00
|
|
|
|
|
|
|
: LEA ( dst src -- )
|
|
|
|
HEX: 8d compile-byte swap register 1-operand ;
|
2005-05-04 22:34:55 -04:00
|
|
|
|
|
|
|
( x87 Floating Point Unit )
|
|
|
|
|
|
|
|
: FSTPS ( operand -- )
|
|
|
|
HEX: d9 compile-byte HEX: 1c compile-byte
|
|
|
|
BIN: 100 1-operand ;
|
|
|
|
|
|
|
|
: FSTPL ( operand -- )
|
|
|
|
HEX: dd compile-byte HEX: 1c compile-byte
|
|
|
|
BIN: 100 1-operand ;
|