aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgrischka <grischka>2009-12-19 22:08:37 +0100
committergrischka <grischka>2009-12-19 22:16:20 +0100
commit1308e8ebcfba43b4b96b7ef32f1a177b1168665d (patch)
treeeed594426e6d4d6f266be4cc0cfe0cde9627ad43
parente81569bc70697d4380e7456e7938dec29c91af73 (diff)
downloadtinycc-1308e8ebcfba43b4b96b7ef32f1a177b1168665d.tar.gz
tinycc-1308e8ebcfba43b4b96b7ef32f1a177b1168665d.tar.bz2
integrate x86_64-asm.c into i386-asm.c
Also, disable 16bit support for now as it causes bugs in 32bit mode. #define I386_ASM_16 if you want it.
-rw-r--r--Makefile4
-rw-r--r--i386-asm.c616
-rw-r--r--i386-asm.h29
-rw-r--r--i386-gen.c13
-rw-r--r--i386-tok.h133
-rw-r--r--libtcc.c16
-rw-r--r--tcc.h24
-rw-r--r--tcctok.h6
-rw-r--r--win32/build-tcc.bat16
-rw-r--r--x86_64-asm.c1266
-rw-r--r--x86_64-gen.c15
-rw-r--r--x86_64-tok.h225
12 files changed, 521 insertions, 1842 deletions
diff --git a/Makefile b/Makefile
index a6033da..e6dba91 100644
--- a/Makefile
+++ b/Makefile
@@ -82,9 +82,9 @@ CORE_FILES = tcc.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c \
tcc.h config.h libtcc.h tcctok.h
I386_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h i386-tok.h
WIN32_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h i386-tok.h tccpe.c
-WIN64_FILES = $(CORE_FILES) x86_64-gen.c x86_64-asm.c x86_64-asm.h x86_64-tok.h tccpe.c
+WIN64_FILES = $(CORE_FILES) x86_64-gen.c i386-asm.c x86_64-asm.h tccpe.c
WINCE_FILES = $(CORE_FILES) arm-gen.c tccpe.c
-X86_64_FILES = $(CORE_FILES) x86_64-gen.c x86_64-asm.c x86_64-asm.h x86_64-tok.h
+X86_64_FILES = $(CORE_FILES) x86_64-gen.c i386-asm.c x86_64-asm.h
ARM_FILES = $(CORE_FILES) arm-gen.c
C67_FILES = $(CORE_FILES) c67-gen.c tcccoff.c
diff --git a/i386-asm.c b/i386-asm.c
index b18a4bc..6e1314c 100644
--- a/i386-asm.c
+++ b/i386-asm.c
@@ -1,7 +1,8 @@
/*
* i386 specific functions for TCC assembler
- *
+ *
* Copyright (c) 2001, 2002 Fabrice Bellard
+ * Copyright (c) 2009 Frédéric Feret (x86_64 support)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -20,64 +21,74 @@
#define MAX_OPERANDS 3
-typedef struct ASMInstr {
- uint16_t sym;
- uint16_t opcode;
- uint16_t instr_type;
-#define OPC_JMP 0x01 /* jmp operand */
-#define OPC_B 0x02 /* only used zith OPC_WL */
-#define OPC_WL 0x04 /* accepts w, l or no suffix */
-#define OPC_BWL (OPC_B | OPC_WL) /* accepts b, w, l or no suffix */
-#define OPC_REG 0x08 /* register is added to opcode */
-#define OPC_MODRM 0x10 /* modrm encoding */
-#define OPC_FWAIT 0x20 /* add fwait opcode */
-#define OPC_TEST 0x40 /* test opcodes */
-#define OPC_SHIFT 0x80 /* shift opcodes */
+#define TOK_ASM_first TOK_ASM_clc
+#define TOK_ASM_last TOK_ASM_emms
+
+#define OPC_JMP 0x01 /* jmp operand */
+#define OPC_B 0x02 /* only used with OPC_WL */
+#define OPC_WL 0x04 /* accepts w, l or no suffix */
+#define OPC_BWL (OPC_B | OPC_WL) /* accepts b, w, l or no suffix */
+#define OPC_REG 0x08 /* register is added to opcode */
+#define OPC_MODRM 0x10 /* modrm encoding */
+#define OPC_FWAIT 0x20 /* add fwait opcode */
+#define OPC_TEST 0x40 /* test opcodes */
+#define OPC_SHIFT 0x80 /* shift opcodes */
#define OPC_D16 0x0100 /* generate data16 prefix */
#define OPC_ARITH 0x0200 /* arithmetic opcodes */
#define OPC_SHORTJMP 0x0400 /* short jmp operand */
#define OPC_FARITH 0x0800 /* FPU arithmetic opcodes */
+#ifdef TCC_TARGET_X86_64
+# define OPC_WLQ 0x1000 /* accepts w, l, q or no suffix */
+# define OPC_BWLQ (OPC_B | OPC_WLQ) /* accepts b, w, l, q or no suffix */
+# define OPC_WLX OPC_WLQ
+#else
+# define OPC_WLX OPC_WL
+#endif
+
#define OPC_GROUP_SHIFT 13
/* in order to compress the operand type, we use specific operands and
- we or only with EA */
-#define OPT_REG8 0 /* warning: value is hardcoded from TOK_ASM_xxx */
-#define OPT_REG16 1 /* warning: value is hardcoded from TOK_ASM_xxx */
-#define OPT_REG32 2 /* warning: value is hardcoded from TOK_ASM_xxx */
-#define OPT_MMX 3 /* warning: value is hardcoded from TOK_ASM_xxx */
-#define OPT_SSE 4 /* warning: value is hardcoded from TOK_ASM_xxx */
-#define OPT_CR 5 /* warning: value is hardcoded from TOK_ASM_xxx */
-#define OPT_TR 6 /* warning: value is hardcoded from TOK_ASM_xxx */
-#define OPT_DB 7 /* warning: value is hardcoded from TOK_ASM_xxx */
-#define OPT_SEG 8
-#define OPT_ST 9
-#define OPT_IM8 10
-#define OPT_IM8S 11
-#define OPT_IM16 12
-#define OPT_IM32 13
-#define OPT_EAX 14 /* %al, %ax or %eax register */
-#define OPT_ST0 15 /* %st(0) register */
-#define OPT_CL 16 /* %cl register */
-#define OPT_DX 17 /* %dx register */
-#define OPT_ADDR 18 /* OP_EA with only offset */
-#define OPT_INDIR 19 /* *(expr) */
-
-/* composite types */
-#define OPT_COMPOSITE_FIRST 20
-#define OPT_IM 20 /* IM8 | IM16 | IM32 */
-#define OPT_REG 21 /* REG8 | REG16 | REG32 */
-#define OPT_REGW 22 /* REG16 | REG32 */
-#define OPT_IMW 23 /* IM16 | IM32 */
-
-/* can be ored with any OPT_xxx */
-#define OPT_EA 0x80
-
- uint8_t nb_ops;
- uint8_t op_type[MAX_OPERANDS]; /* see OP_xxx */
-} ASMInstr;
+ we or only with EA */
+enum {
+ OPT_REG8=0, /* warning: value is hardcoded from TOK_ASM_xxx */
+ OPT_REG16, /* warning: value is hardcoded from TOK_ASM_xxx */
+ OPT_REG32, /* warning: value is hardcoded from TOK_ASM_xxx */
+#ifdef TCC_TARGET_X86_64
+ OPT_REG64, /* warning: value is hardcoded from TOK_ASM_xxx */
+#endif
+ OPT_MMX, /* warning: value is hardcoded from TOK_ASM_xxx */
+ OPT_SSE, /* warning: value is hardcoded from TOK_ASM_xxx */
+ OPT_CR, /* warning: value is hardcoded from TOK_ASM_xxx */
+ OPT_TR, /* warning: value is hardcoded from TOK_ASM_xxx */
+ OPT_DB, /* warning: value is hardcoded from TOK_ASM_xxx */
+ OPT_SEG,
+ OPT_ST,
+ OPT_IM8,
+ OPT_IM8S,
+ OPT_IM16,
+ OPT_IM32,
+#ifdef TCC_TARGET_X86_64
+ OPT_IM64,
+#endif
+ OPT_EAX, /* %al, %ax, %eax or %rax register */
+ OPT_ST0, /* %st(0) register */
+ OPT_CL, /* %cl register */
+ OPT_DX, /* %dx register */
+ OPT_ADDR, /* OP_EA with only offset */
+ OPT_INDIR, /* *(expr) */
+ /* composite types */
+ OPT_COMPOSITE_FIRST,
+ OPT_IM, /* IM8 | IM16 | IM32 | IM64 */
+ OPT_REG, /* REG8 | REG16 | REG32 | REG64 */
+ OPT_REGW, /* REG16 | REG32 | REG64 */
+ OPT_IMW, /* IM16 | IM32 | IM64 */
+#ifdef TCC_TARGET_X86_64
+ OPT_IMNO64, /* IM16 | IM32 */
+#endif
+ /* can be ored with any OPT_xxx */
+ OPT_EA = 0x80
+};
-typedef struct Operand {
- uint32_t type;
#define OP_REG8 (1 << OPT_REG8)
#define OP_REG16 (1 << OPT_REG16)
#define OP_REG32 (1 << OPT_REG32)
@@ -98,23 +109,55 @@ typedef struct Operand {
#define OP_DX (1 << OPT_DX)
#define OP_ADDR (1 << OPT_ADDR)
#define OP_INDIR (1 << OPT_INDIR)
+#ifdef TCC_TARGET_X86_64
+# define OP_REG64 (1 << OPT_REG64)
+# define OP_IM64 (1 << OPT_IM64)
+#else
+# define OP_REG64 0
+# define OP_IM64 0
+#endif
#define OP_EA 0x40000000
-#define OP_REG (OP_REG8 | OP_REG16 | OP_REG32)
-#define OP_IM OP_IM32
+#define OP_REG (OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64)
+
+#ifdef TCC_TARGET_X86_64
+# define OP_IM OP_IM64
+# define TREG_XAX TREG_RAX
+# define TREG_XCX TREG_RCX
+# define TREG_XDX TREG_RDX
+#else
+# define OP_IM OP_IM32
+# define TREG_XAX TREG_EAX
+# define TREG_XCX TREG_ECX
+# define TREG_XDX TREG_EDX
+#endif
+
+typedef struct ASMInstr {
+ uint16_t sym;
+ uint16_t opcode;
+ uint16_t instr_type;
+ uint8_t nb_ops;
+ uint8_t op_type[MAX_OPERANDS]; /* see OP_xxx */
+} ASMInstr;
+
+typedef struct Operand {
+ uint32_t type;
int8_t reg; /* register, -1 if none */
int8_t reg2; /* second register, -1 if none */
uint8_t shift;
ExprValue e;
} Operand;
-static const uint8_t reg_to_size[5] = {
+static const uint8_t reg_to_size[9] = {
/*
[OP_REG8] = 0,
[OP_REG16] = 1,
[OP_REG32] = 2,
+#ifdef TCC_TARGET_X86_64
+ [OP_REG64] = 3,
+#endif
*/
- 0, 0, 1, 0, 2
+ 0, 0, 1, 0, 2, 0, 0, 0, 3
};
#define NB_TEST_OPCODES 30
@@ -168,8 +211,11 @@ static const ASMInstr asm_instrs[] = {
#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 1, { op0 }},
#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 2, { op0, op1 }},
#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 3, { op0, op1, op2 }},
-#include "i386-asm.h"
-
+#ifdef TCC_TARGET_X86_64
+# include "x86_64-asm.h"
+#else
+# include "i386-asm.h"
+#endif
/* last operation */
{ 0, },
};
@@ -181,17 +227,20 @@ static const uint16_t op0_codes[] = {
#define DEF_ASM_OP1(name, opcode, group, instr_type, op0)
#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1)
#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2)
-#include "i386-asm.h"
+#ifdef TCC_TARGET_X86_64
+# include "x86_64-asm.h"
+#else
+# include "i386-asm.h"
+#endif
};
static inline int get_reg_shift(TCCState *s1)
{
int shift, v;
-
- if (s1->seg_size == 16) {
+#ifdef I386_ASM_16
+ if (s1->seg_size == 16)
error("invalid effective address");
- }
-
+#endif
v = asm_int_expr(s1);
switch(v) {
case 1:
@@ -216,23 +265,26 @@ static inline int get_reg_shift(TCCState *s1)
static int asm_parse_reg(void)
{
- int reg;
+ int reg = 0;
if (tok != '%')
goto error_32;
next();
if (tok >= TOK_ASM_eax && tok <= TOK_ASM_edi) {
reg = tok - TOK_ASM_eax;
- next();
- return reg;
+#ifdef TCC_TARGET_X86_64
+ } else if (tok >= TOK_ASM_rax && tok <= TOK_ASM_rdi) {
+ reg = tok - TOK_ASM_rax;
+#endif
+#ifdef I386_ASM_16
} else if (tok >= TOK_ASM_ax && tok <= TOK_ASM_di) {
reg = tok - TOK_ASM_ax;
- next();
- return reg;
+#endif
} else {
error_32:
expect("register");
- return 0;
}
+ next();
+ return reg;
}
static void parse_operand(TCCState *s1, Operand *op)
@@ -253,11 +305,11 @@ static void parse_operand(TCCState *s1, Operand *op)
reg = tok - TOK_ASM_al;
op->type = 1 << (reg >> 3); /* WARNING: do not change constant order */
op->reg = reg & 7;
- if ((op->type & OP_REG) && op->reg == TREG_EAX)
+ if ((op->type & OP_REG) && op->reg == TREG_XAX)
op->type |= OP_EAX;
- else if (op->type == OP_REG8 && op->reg == TREG_ECX)
+ else if (op->type == OP_REG8 && op->reg == TREG_XCX)
op->type |= OP_CL;
- else if (op->type == OP_REG16 && op->reg == TREG_EDX)
+ else if (op->type == OP_REG16 && op->reg == TREG_XDX)
op->type |= OP_DX;
} else if (tok >= TOK_ASM_dr0 && tok <= TOK_ASM_dr7) {
op->type = OP_DB;
@@ -294,7 +346,7 @@ static void parse_operand(TCCState *s1, Operand *op)
/* constant value */
next();
asm_expr(s1, &e);
- op->type = OP_IM32;
+ op->type = OP_IM;
op->e.v = e.v;
op->e.sym = e.sym;
if (!op->e.sym) {
@@ -304,6 +356,10 @@ static void parse_operand(TCCState *s1, Operand *op)
op->type |= OP_IM8S;
if (op->e.v == (uint16_t)op->e.v)
op->type |= OP_IM16;
+#ifdef TCC_TARGET_X86_64
+ if (op->e.v == (uint32_t)op->e.v)
+ op->type |= OP_IM32;
+#endif
}
} else {
/* address(reg,reg2,shift) with all variants */
@@ -328,7 +384,7 @@ static void parse_operand(TCCState *s1, Operand *op)
next();
if (tok != ',') {
op->reg2 = asm_parse_reg();
- }
+ }
if (tok == ',') {
next();
op->shift = get_reg_shift(s1);
@@ -342,51 +398,40 @@ static void parse_operand(TCCState *s1, Operand *op)
op->type |= indir;
}
-static void gen_le16(int v)
-{
- g(v);
- g(v >> 8);
-}
-
-/* XXX: unify with C code output ? */
static void gen_expr32(ExprValue *pe)
{
- if (pe->sym)
- greloc(cur_text_section, pe->sym, ind, R_386_32);
- gen_le32(pe->v);
+ gen_addr32(pe->sym ? VT_SYM : 0, pe->sym, pe->v);
}
-static void gen_expr16(ExprValue *pe)
+#ifdef TCC_TARGET_X86_64
+static void gen_expr64(ExprValue *pe)
{
- if (pe->sym)
- greloc(cur_text_section, pe->sym, ind, R_386_16);
- gen_le16(pe->v);
+ gen_addr64(pe->sym ? VT_SYM : 0, pe->sym, pe->v);
}
+#endif
/* XXX: unify with C code output ? */
static void gen_disp32(ExprValue *pe)
{
- Sym *sym;
- sym = pe->sym;
- if (sym) {
- if (sym->r == cur_text_section->sh_num) {
- /* same section: we can output an absolute value. Note
- that the TCC compiler behaves differently here because
- it always outputs a relocation to ease (future) code
- elimination in the linker */
- gen_le32(pe->v + sym->jnext - ind - 4);
- } else {
- greloc(cur_text_section, sym, ind, R_386_PC32);
- gen_le32(pe->v - 4);
- }
+ Sym *sym = pe->sym;
+ if (sym && sym->r == cur_text_section->sh_num) {
+ /* same section: we can output an absolute value. Note
+ that the TCC compiler behaves differently here because
+ it always outputs a relocation to ease (future) code
+ elimination in the linker */
+ gen_le32(pe->v + sym->jnext - ind - 4);
} else {
- /* put an empty PC32 relocation */
- put_elf_reloc(symtab_section, cur_text_section,
- ind, R_386_PC32, 0);
- gen_le32(pe->v - 4);
+ gen_addrpc32(VT_SYM, sym, pe->v);
}
}
+#ifdef I386_ASM_16
+static void gen_expr16(ExprValue *pe)
+{
+ if (pe->sym)
+ greloc(cur_text_section, pe->sym, ind, R_386_16);
+ gen_le16(pe->v);
+}
static void gen_disp16(ExprValue *pe)
{
Sym *sym;
@@ -409,6 +454,7 @@ static void gen_disp16(ExprValue *pe)
gen_le16(pe->v - 2);
}
}
+#endif
/* generate the modrm operand */
static inline void asm_modrm(int reg, Operand *op)
@@ -419,10 +465,13 @@ static inline void asm_modrm(int reg, Operand *op)
g(0xc0 + (reg << 3) + op->reg);
} else if (op->reg == -1 && op->reg2 == -1) {
/* displacement only */
+#ifdef I386_ASM_16
if (tcc_state->seg_size == 16) {
g(0x06 + (reg << 3));
gen_expr16(&op->e);
- } else if (tcc_state->seg_size == 32) {
+ } else if (tcc_state->seg_size == 32)
+#endif
+ {
g(0x05 + (reg << 3));
gen_expr32(&op->e);
}
@@ -443,15 +492,18 @@ static inline void asm_modrm(int reg, Operand *op)
reg1 = op->reg;
if (op->reg2 != -1)
reg1 = 4;
+#ifdef I386_ASM_16
if (tcc_state->seg_size == 32) {
- g(mod + (reg << 3) + reg1);
- if (reg1 == 4) {
- /* add sib byte */
- reg2 = op->reg2;
- if (reg2 == -1)
- reg2 = 4; /* indicate no index */
- g((op->shift << 6) + (reg2 << 3) + sib_reg1);
- }
+#endif
+ g(mod + (reg << 3) + reg1);
+ if (reg1 == 4) {
+ /* add sib byte */
+ reg2 = op->reg2;
+ if (reg2 == -1)
+ reg2 = 4; /* indicate no index */
+ g((op->shift << 6) + (reg2 << 3) + sib_reg1);
+ }
+#ifdef I386_ASM_16
} else if (tcc_state->seg_size == 16) {
/* edi = 7, esi = 6 --> di = 5, si = 4 */
if ((reg1 == 6) || (reg1 == 7)) {
@@ -465,7 +517,7 @@ static inline void asm_modrm(int reg, Operand *op)
/* sib not valid in 16-bit mode */
} else if (reg1 == 4) {
reg2 = op->reg2;
- /* bp + si + offset */
+ /* bp + si + offset */
if ((sib_reg1 == 5) && (reg2 == 6)) {
reg1 = 2;
/* bp + di + offset */
@@ -487,14 +539,16 @@ static inline void asm_modrm(int reg, Operand *op)
}
g(mod + (reg << 3) + reg1);
}
-
+#endif
/* add offset */
if (mod == 0x40) {
g(op->e.v);
} else if (mod == 0x80 || op->reg == -1) {
+#ifdef I386_ASM_16
if (tcc_state->seg_size == 16)
gen_expr16(&op->e);
else if (tcc_state->seg_size == 32)
+#endif
gen_expr32(&op->e);
}
}
@@ -507,9 +561,9 @@ static void asm_opcode(TCCState *s1, int opcode)
int nb_ops, s;
Operand ops[MAX_OPERANDS], *pop;
int op_type[3]; /* decoded op type */
-
- int a32, o32;
- static int addr32 = 0, data32 = 0;
+#ifdef I386_ASM_16
+ static int a32 = 0, o32 = 0, addr32 = 0, data32 = 0;
+#endif
/* get operands */
pop = ops;
@@ -523,14 +577,12 @@ static void asm_opcode(TCCState *s1, int opcode)
}
parse_operand(s1, pop);
if (tok == ':') {
- if (pop->type != OP_SEG || seg_prefix) {
- bad_prefix:
+ if (pop->type != OP_SEG || seg_prefix)
error("incorrect prefix");
- }
seg_prefix = segment_prefixes[pop->reg];
next();
parse_operand(s1, pop);
-#if 0
+#ifndef I386_ASM_16
if (!(pop->type & OP_EA)) {
error("segment prefix must be followed by memory reference");
}
@@ -545,7 +597,7 @@ static void asm_opcode(TCCState *s1, int opcode)
is_short_jmp = 0;
s = 0; /* avoid warning */
-
+
/* optimize matching by using a lookup table (no hashing is needed
!) */
for(pa = asm_instrs; pa->sym != 0; pa++) {
@@ -555,23 +607,22 @@ static void asm_opcode(TCCState *s1, int opcode)
if (!((unsigned)v < 8 * 6 && (v % 6) == 0))
continue;
} else if (pa->instr_type & OPC_ARITH) {
- if (!(opcode >= pa->sym && opcode < pa->sym + 8 * 4))
+ if (!(opcode >= pa->sym && opcode < pa->sym + 8*NBWLX))
continue;
- goto compute_size;
+ s = (opcode - pa->sym) % NBWLX;
} else if (pa->instr_type & OPC_SHIFT) {
- if (!(opcode >= pa->sym && opcode < pa->sym + 7 * 4))
+ if (!(opcode >= pa->sym && opcode < pa->sym + 7*NBWLX))
continue;
- goto compute_size;
+ s = (opcode - pa->sym) % NBWLX;
} else if (pa->instr_type & OPC_TEST) {
if (!(opcode >= pa->sym && opcode < pa->sym + NB_TEST_OPCODES))
continue;
} else if (pa->instr_type & OPC_B) {
- if (!(opcode >= pa->sym && opcode <= pa->sym + 3))
+ if (!(opcode >= pa->sym && opcode < pa->sym + NBWLX))
continue;
- compute_size:
- s = (opcode - pa->sym) & 3;
- } else if (pa->instr_type & OPC_WL) {
- if (!(opcode >= pa->sym && opcode <= pa->sym + 2))
+ s = opcode - pa->sym;
+ } else if (pa->instr_type & OPC_WLX) {
+ if (!(opcode >= pa->sym && opcode < pa->sym + NBWLX-1))
continue;
s = opcode - pa->sym + 1;
} else {
@@ -587,17 +638,22 @@ static void asm_opcode(TCCState *s1, int opcode)
op2 = op1 & 0x1f;
switch(op2) {
case OPT_IM:
- v = OP_IM8 | OP_IM16 | OP_IM32;
+ v = OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64;
break;
case OPT_REG:
- v = OP_REG8 | OP_REG16 | OP_REG32;
+ v = OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64;
break;
case OPT_REGW:
- v = OP_REG16 | OP_REG32;
+ v = OP_REG16 | OP_REG32 | OP_REG64;
break;
case OPT_IMW:
+ v = OP_IM16 | OP_IM32 | OP_IM64;
+ break;
+#ifdef TCC_TARGET_X86_64
+ case OPT_IMNO64:
v = OP_IM16 | OP_IM32;
break;
+#endif
default:
v = 1 << op2;
break;
@@ -613,51 +669,66 @@ static void asm_opcode(TCCState *s1, int opcode)
next: ;
}
if (pa->sym == 0) {
- if (opcode >= TOK_ASM_pusha && opcode <= TOK_ASM_emms) {
+ if (opcode >= TOK_ASM_first && opcode <= TOK_ASM_last) {
int b;
- b = op0_codes[opcode - TOK_ASM_pusha];
+ b = op0_codes[opcode - TOK_ASM_first];
+#ifdef I386_ASM_16
if (opcode == TOK_ASM_o32) {
if (s1->seg_size == 32)
- goto bad_prefix;
+ error("incorrect prefix");
else
- data32 = 1;
+ o32 = data32 = 1;
} else if (opcode == TOK_ASM_a32) {
if (s1->seg_size == 32)
- goto bad_prefix;
+ error("incorrect prefix");
else
- addr32 = 1;
+ a32 = addr32 = 1;
}
+#endif
if (b & 0xff00)
g(b >> 8);
g(b);
return;
} else {
- error("unknown opcode '%s'",
+ error("unknown opcode '%s'",
get_tok_str(opcode, NULL));
}
}
/* if the size is unknown, then evaluate it (OPC_B or OPC_WL case) */
- if (s == 3) {
- for(i = 0; s == 3 && i < nb_ops; i++) {
+ if (s == NBWLX-1) {
+ for(i = 0; s == NBWLX-1 && i < nb_ops; i++) {
if ((ops[i].type & OP_REG) && !(op_type[i] & (OP_CL | OP_DX)))
s = reg_to_size[ops[i].type & OP_REG];
}
- if (s == 3) {
- if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) &&
- (ops[0].type & (OP_SEG | OP_IM8S | OP_IM32)))
+ if (s == NBWLX-1) {
+ if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) &&
+ (ops[0].type & (OP_SEG | OP_IM8S | OP_IM32 | OP_IM64)))
s = 2;
else
error("cannot infer opcode suffix");
}
}
- a32 = o32 = 0;
+#ifdef I386_ASM_16
+ for(i = 0; i < nb_ops; i++) {
+ if (ops[i].type & OP_REG32) {
+ if (s1->seg_size == 16)
+ o32 = 1;
+ } else if (!(ops[i].type & OP_REG32)) {
+ if (s1->seg_size == 32)
+ o32 = 1;
+ }
+ }
+
+
if (s == 1 || (pa->instr_type & OPC_D16)) {
if (s1->seg_size == 32)
o32 = 1;
- } else if (s == 2 && !(pa->instr_type & OPC_D16)) {
- if (s1->seg_size == 16)
+ } else if (s == 2) {
+ if (s1->seg_size == 16) {
+ if (!(pa->instr_type & OPC_D16))
o32 = 1;
+ }
}
/* generate a16/a32 prefix if needed */
@@ -668,6 +739,19 @@ static void asm_opcode(TCCState *s1, int opcode)
g(0x66);
addr32 = data32 = 0;
+#else
+ /* generate data16 prefix if needed */
+ if (s == 1 || (pa->instr_type & OPC_D16))
+ g(0x66);
+#ifdef TCC_TARGET_X86_64
+ else if (s == 3) {
+ /* generate REX prefix */
+ if ((opcode != TOK_ASM_push && opcode != TOK_ASM_pop)
+ || !(ops[0].type & OP_REG64))
+ g(0x48);
+ }
+#endif
+#endif
/* now generates the operation */
if (pa->instr_type & OPC_FWAIT)
@@ -694,7 +778,7 @@ static void asm_opcode(TCCState *s1, int opcode)
nb_ops = 0;
} else if (v <= 0x05) {
/* arith case */
- v += ((opcode - TOK_ASM_addb) >> 2) << 3;
+ v += ((opcode - TOK_ASM_addb) / NBWLX) << 3;
} else if ((pa->instr_type & (OPC_FARITH | OPC_MODRM)) == OPC_FARITH) {
/* fpu arith case */
v += ((opcode - pa->sym) / 6) << 3;
@@ -713,7 +797,7 @@ static void asm_opcode(TCCState *s1, int opcode)
if (pa->instr_type & OPC_B)
v += s >= 1;
if (pa->instr_type & OPC_TEST)
- v += test_bits[opcode - pa->sym];
+ v += test_bits[opcode - pa->sym];
if (pa->instr_type & OPC_SHORTJMP) {
Sym *sym;
int jmp_disp;
@@ -736,7 +820,7 @@ static void asm_opcode(TCCState *s1, int opcode)
opcode slightly */
if (v == 0xeb)
v = 0xe9;
- else
+ else
v += 0x0f10;
} else {
error("invalid displacement");
@@ -747,15 +831,15 @@ static void asm_opcode(TCCState *s1, int opcode)
if (op1)
g(op1);
g(v);
-
+
/* search which operand will used for modrm */
modrm_index = 0;
if (pa->instr_type & OPC_SHIFT) {
- reg = (opcode - pa->sym) >> 2;
+ reg = (opcode - pa->sym) / NBWLX;
if (reg == 6)
reg = 7;
} else if (pa->instr_type & OPC_ARITH) {
- reg = (opcode - pa->sym) >> 2;
+ reg = (opcode - pa->sym) / NBWLX;
} else if (pa->instr_type & OPC_FARITH) {
reg = (opcode - pa->sym) / 6;
} else {
@@ -774,14 +858,14 @@ static void asm_opcode(TCCState *s1, int opcode)
}
#ifdef ASM_DEBUG
error("bad op table");
-#endif
+#endif
modrm_found:
modrm_index = i;
/* if a register is used in another operand then it is
used instead of group */
for(i = 0;i < nb_ops; i++) {
v = op_type[i];
- if (i != modrm_index &&
+ if (i != modrm_index &&
(v & (OP_REG | OP_MMX | OP_SSE | OP_CR | OP_TR | OP_DB | OP_SEG))) {
reg = ops[i].reg;
break;
@@ -792,79 +876,94 @@ static void asm_opcode(TCCState *s1, int opcode)
}
/* emit constants */
+#ifndef TCC_TARGET_X86_64
if (pa->opcode == 0x9a || pa->opcode == 0xea) {
/* ljmp or lcall kludge */
- if (s1->seg_size == 16) {
- if (o32 == 0)
- gen_expr16(&ops[1].e);
- else if (o32 == 1)
- gen_expr32(&ops[1].e);
- } else
+#ifdef I386_ASM_16
+ if (s1->seg_size == 16 && o32 == 0)
+ gen_expr16(&ops[1].e);
+ else
+#endif
gen_expr32(&ops[1].e);
- if (ops[0].e.sym) {
- error_relocate:
+ if (ops[0].e.sym)
error("cannot relocate");
- }
gen_le16(ops[0].e.v);
- } else {
- for(i = 0;i < nb_ops; i++) {
- v = op_type[i];
- if (v & (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM8S | OP_ADDR)) {
- /* if multiple sizes are given it means we must look
- at the op size */
- if (v == (OP_IM8 | OP_IM16 | OP_IM32) ||
- v == (OP_IM16 | OP_IM32)) {
- if (s == 0)
- v = OP_IM8;
- else if (s == 1)
- v = OP_IM16;
+ return;
+ }
+#endif
+ for(i = 0;i < nb_ops; i++) {
+ v = op_type[i];
+ if (v & (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64 | OP_IM8S | OP_ADDR)) {
+ /* if multiple sizes are given it means we must look
+ at the op size */
+ if ((v | OP_IM8 | OP_IM64) == (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64)) {
+ if (s == 0)
+ v = OP_IM8;
+ else if (s == 1)
+ v = OP_IM16;
+ else if (s == 2 || (v & OP_IM64) == 0)
+ v = OP_IM32;
+ else
+ v = OP_IM64;
+ }
+ if (v & (OP_IM8 | OP_IM8S)) {
+ if (ops[i].e.sym)
+ goto error_relocate;
+ g(ops[i].e.v);
+ } else if (v & OP_IM16) {
+#ifdef I386_ASM_16
+ if (s1->seg_size == 16)
+ gen_expr16(&ops[i].e);
+ else
+#endif
+ if (ops[i].e.sym)
+ error_relocate:
+ error("cannot relocate");
+ else
+ gen_le16(ops[i].e.v);
+ } else {
+ if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) {
+ if (is_short_jmp)
+ g(ops[i].e.v);
+#ifdef I386_ASM_16
+ else if (s1->seg_size == 16)
+ gen_disp16(&ops[i].e);
+#endif
else
- v = OP_IM32;
- }
- if (v & (OP_IM8 | OP_IM8S)) {
- if (ops[i].e.sym)
- goto error_relocate;
- g(ops[i].e.v);
- } else if (v & OP_IM16) {
- if (s1->seg_size == 16)
- gen_expr16(&ops[i].e);
- else {
- if (ops[i].e.sym)
- goto error_relocate;
- gen_le16(ops[i].e.v);
- }
+ gen_disp32(&ops[i].e);
} else {
- if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) {
- if (is_short_jmp)
- g(ops[i].e.v);
- else {
- if (s1->seg_size == 16)
- gen_disp16(&ops[i].e);
- else
- gen_disp32(&ops[i].e);
- }
- } else {
- if (s1->seg_size == 16) {
- if ((o32 == 1) && (v & OP_IM32))
- gen_expr32(&ops[i].e);
- else
- gen_expr16(&ops[i].e);
- } else if (s1->seg_size == 32) {
- if (o32 == 1)
- gen_expr16(&ops[i].e);
- else
- gen_expr32(&ops[i].e);
- }
- }
- }
- } else if (v & (OP_REG16 | OP_REG32)) {
- if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) {
- /* jmp $r */
- g(0xE0 + ops[i].reg);
+#ifdef I386_ASM_16
+ if (s1->seg_size == 16 && !((o32 == 1) && (v & OP_IM32)))
+ gen_expr16(&ops[i].e);
+ else
+#endif
+#ifdef TCC_TARGET_X86_64
+ if (v & OP_IM64)
+ gen_expr64(&ops[i].e);
+ else
+#endif
+ gen_expr32(&ops[i].e);
}
}
+#ifdef I386_ASM_16
+ } else if (v & (OP_REG16 | OP_REG32)) {
+ if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) {
+ /* jmp $r */
+ g(0xE0 + ops[i].reg);
+ }
+#endif
+#ifdef TCC_TARGET_X86_64
+ } else if (v & (OP_REG32 | OP_REG64)) {
+ if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) {
+ /* jmp $r */
+ g(0xE0 + ops[i].reg);
+ }
+#endif
}
}
+#ifdef I386_ASM_16
+ a32 = o32 = 0;
+#endif
}
#define NB_SAVED_REGS 3
@@ -931,8 +1030,8 @@ static const char *skip_constraint_modifiers(const char *p)
#define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask)
-static void asm_compute_constraints(ASMOperand *operands,
- int nb_operands, int nb_outputs,
+static void asm_compute_constraints(ASMOperand *operands,
+ int nb_operands, int nb_outputs,
const uint8_t *clobber_regs,
int *pout_reg)
{
@@ -941,7 +1040,7 @@ static void asm_compute_constraints(ASMOperand *operands,
int i, j, k, p1, p2, tmp, reg, c, reg_mask;
const char *str;
uint8_t regs_allocated[NB_ASM_REGS];
-
+
/* init fields */
for(i=0;i<nb_operands;i++) {
op = &operands[i];
@@ -972,13 +1071,13 @@ static void asm_compute_constraints(ASMOperand *operands,
op->priority = constraint_priority(str);
}
}
-
+
/* sort operands according to their priority */
for(i=0;i<nb_operands;i++)
sorted_op[i] = i;
for(i=0;i<nb_operands - 1;i++) {
for(j=i+1;j<nb_operands;j++) {
- p1 = operands[sorted_op[i]].priority;
+ p1 = operands[sorted_op[i]].priority;
p2 = operands[sorted_op[j]].priority;
if (p2 < p1) {
tmp = sorted_op[i];
@@ -995,9 +1094,9 @@ static void asm_compute_constraints(ASMOperand *operands,
regs_allocated[i] = 0;
}
/* esp cannot be used */
- regs_allocated[4] = REG_IN_MASK | REG_OUT_MASK;
+ regs_allocated[4] = REG_IN_MASK | REG_OUT_MASK;
/* ebp cannot be used yet */
- regs_allocated[5] = REG_IN_MASK | REG_OUT_MASK;
+ regs_allocated[5] = REG_IN_MASK | REG_OUT_MASK;
/* allocate registers and generate corresponding asm moves */
for(i=0;i<nb_operands;i++) {
@@ -1030,25 +1129,25 @@ static void asm_compute_constraints(ASMOperand *operands,
goto try_next;
case 'A':
/* allocate both eax and edx */
- if (is_reg_allocated(TREG_EAX) ||
- is_reg_allocated(TREG_EDX))
+ if (is_reg_allocated(TREG_XAX) ||
+ is_reg_allocated(TREG_XDX))
goto try_next;
op->is_llong = 1;
- op->reg = TREG_EAX;
- regs_allocated[TREG_EAX] |= reg_mask;
- regs_allocated[TREG_EDX] |= reg_mask;
+ op->reg = TREG_XAX;
+ regs_allocated[TREG_XAX] |= reg_mask;
+ regs_allocated[TREG_XDX] |= reg_mask;
break;
case 'a':
- reg = TREG_EAX;
+ reg = TREG_XAX;
goto alloc_reg;
case 'b':
reg = 3;
goto alloc_reg;
case 'c':
- reg = TREG_ECX;
+ reg = TREG_XCX;
goto alloc_reg;
case 'd':
- reg = TREG_EDX;
+ reg = TREG_XDX;
goto alloc_reg;
case 'S':
reg = 6;
@@ -1116,7 +1215,7 @@ static void asm_compute_constraints(ASMOperand *operands,
}
break;
default:
- error("asm constraint %d ('%s') could not be satisfied",
+ error("asm constraint %d ('%s') could not be satisfied",
j, op->constraint);
break;
}
@@ -1126,13 +1225,13 @@ static void asm_compute_constraints(ASMOperand *operands,
operands[op->input_index].is_llong = op->is_llong;
}
}
-
+
/* compute out_reg. It is used to store outputs registers to memory
locations references by pointers (VT_LLOCAL case) */
*pout_reg = -1;
for(i=0;i<nb_operands;i++) {
op = &operands[i];
- if (op->reg >= 0 &&
+ if (op->reg >= 0 &&
(op->vt->r & VT_VALMASK) == VT_LLOCAL &&
!op->is_memory) {
for(reg = 0; reg < 8; reg++) {
@@ -1145,15 +1244,15 @@ static void asm_compute_constraints(ASMOperand *operands,
break;
}
}
-
+
/* print sorted constraints */
#ifdef ASM_DEBUG
for(i=0;i<nb_operands;i++) {
j = sorted_op[i];
op = &operands[j];
- printf("%%%d [%s]: \"%s\" r=0x%04x reg=%d\n",
- j,
- op->id ? get_tok_str(op->id, NULL) : "",
+ printf("%%%d [%s]: \"%s\" r=0x%04x reg=%d\n",
+ j,
+ op->id ? get_tok_str(op->id, NULL) : "",
op->constraint,
op->vt->r,
op->reg);
@@ -1163,7 +1262,7 @@ static void asm_compute_constraints(ASMOperand *operands,
#endif
}
-static void subst_asm_operand(CString *add_str,
+static void subst_asm_operand(CString *add_str,
SValue *sv, int modifier)
{
int r, reg, size, val;
@@ -1193,7 +1292,7 @@ static void subst_asm_operand(CString *add_str,
reg = r & VT_VALMASK;
if (reg >= VT_CONST)
error("internal compiler error");
- snprintf(buf, sizeof(buf), "(%%%s)",
+ snprintf(buf, sizeof(buf), "(%%%s)",
get_tok_str(TOK_ASM_eax + reg, NULL));
cstr_cat(add_str, buf);
} else {
@@ -1207,6 +1306,10 @@ static void subst_asm_operand(CString *add_str,
size = 1;
else if ((sv->type.t & VT_BTYPE) == VT_SHORT)
size = 2;
+#ifdef TCC_TARGET_X86_64
+ else if ((sv->type.t & VT_BTYPE) == VT_LLONG)
+ size = 8;
+#endif
else
size = 4;
if (size == 1 && reg >= 4)
@@ -1222,6 +1325,10 @@ static void subst_asm_operand(CString *add_str,
size = -1;
} else if (modifier == 'w') {
size = 2;
+#ifdef TCC_TARGET_X86_64
+ } else if (modifier == 'q') {
+ size = 8;
+#endif
}
switch(size) {
@@ -1237,6 +1344,11 @@ static void subst_asm_operand(CString *add_str,
default:
reg = TOK_ASM_eax + reg;
break;
+#ifdef TCC_TARGET_X86_64
+ case 8:
+ reg = TOK_ASM_rax + reg;
+ break;
+#endif
}
snprintf(buf, sizeof(buf), "%%%s", get_tok_str(reg, NULL));
cstr_cat(add_str, buf);
@@ -1244,7 +1356,7 @@ static void subst_asm_operand(CString *add_str,
}
/* generate prolog and epilog code for asm statment */
-static void asm_gen_code(ASMOperand *operands, int nb_operands,
+static void asm_gen_code(ASMOperand *operands, int nb_operands,
int nb_outputs, int is_output,
uint8_t *clobber_regs,
int out_reg)
@@ -1266,8 +1378,10 @@ static void asm_gen_code(ASMOperand *operands, int nb_operands,
for(i = 0; i < NB_SAVED_REGS; i++) {
reg = reg_saved[i];
if (regs_allocated[reg]) {
+#ifdef I386_ASM_16
if (tcc_state->seg_size == 16)
g(0x66);
+#endif
g(0x50 + reg);
}
}
@@ -1291,7 +1405,7 @@ static void asm_gen_code(ASMOperand *operands, int nb_operands,
SValue sv;
sv = *op->vt;
sv.c.ul += 4;
- load(TREG_EDX, &sv);
+ load(TREG_XDX, &sv);
}
}
}
@@ -1317,7 +1431,7 @@ static void asm_gen_code(ASMOperand *operands, int nb_operands,
SValue sv;
sv = *op->vt;
sv.c.ul += 4;
- store(TREG_EDX, &sv);
+ store(TREG_XDX, &sv);
}
}
}
@@ -1326,8 +1440,10 @@ static void asm_gen_code(ASMOperand *operands, int nb_operands,
for(i = NB_SAVED_REGS - 1; i >= 0; i--) {
reg = reg_saved[i];
if (regs_allocated[reg]) {
+#ifdef I386_ASM_16
if (tcc_state->seg_size == 16)
g(0x66);
+#endif
g(0x58 + reg);
}
}
@@ -1339,7 +1455,7 @@ static void asm_clobber(uint8_t *clobber_regs, const char *str)
int reg;
TokenSym *ts;
- if (!strcmp(str, "memory") ||
+ if (!strcmp(str, "memory") ||
!strcmp(str, "cc"))
return;
ts = tok_alloc(str, strlen(str));
@@ -1348,6 +1464,10 @@ static void asm_clobber(uint8_t *clobber_regs, const char *str)
reg -= TOK_ASM_eax;
} else if (reg >= TOK_ASM_ax && reg <= TOK_ASM_di) {
reg -= TOK_ASM_ax;
+#ifdef TCC_TARGET_X86_64
+ } else if (reg >= TOK_ASM_rax && reg <= TOK_ASM_rdi) {
+ reg -= TOK_ASM_rax;
+#endif
} else {
error("invalid clobber register '%s'", str);
}
diff --git a/i386-asm.h b/i386-asm.h
index dfcaac8..1b72633 100644
--- a/i386-asm.h
+++ b/i386-asm.h
@@ -1,12 +1,12 @@
- DEF_ASM_OP0(pusha, 0x60) /* must be first OP0 */
- DEF_ASM_OP0(popa, 0x61)
- DEF_ASM_OP0(clc, 0xf8)
+ DEF_ASM_OP0(clc, 0xf8) /* must be first OP0 */
DEF_ASM_OP0(cld, 0xfc)
DEF_ASM_OP0(cli, 0xfa)
DEF_ASM_OP0(clts, 0x0f06)
DEF_ASM_OP0(cmc, 0xf5)
DEF_ASM_OP0(lahf, 0x9f)
DEF_ASM_OP0(sahf, 0x9e)
+ DEF_ASM_OP0(pusha, 0x60)
+ DEF_ASM_OP0(popa, 0x61)
DEF_ASM_OP0(pushfl, 0x9c)
DEF_ASM_OP0(popfl, 0x9d)
DEF_ASM_OP0(pushf, 0x9c)
@@ -74,12 +74,15 @@ ALT(DEF_ASM_OP2(btcw, 0x0fbb, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_REGW | OPT_EA
ALT(DEF_ASM_OP2(btcw, 0x0fba, 7, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW | OPT_EA))
/* prefixes */
- DEF_ASM_OP0(addr16, 0x67)
+#ifdef I386_ASM_16
DEF_ASM_OP0(a32, 0x67)
-
- DEF_ASM_OP0(data16, 0x66)
DEF_ASM_OP0(o32, 0x66)
-
+#else
+ DEF_ASM_OP0(aword, 0x67)
+ DEF_ASM_OP0(addr16, 0x67)
+ ALT(DEF_ASM_OP0(word, 0x66))
+ DEF_ASM_OP0(data16, 0x66)
+#endif
DEF_ASM_OP0(lock, 0xf0)
DEF_ASM_OP0(rep, 0xf3)
DEF_ASM_OP0(repe, 0xf3)
@@ -122,9 +125,9 @@ ALT(DEF_ASM_OP2(movzwl, 0x0fb7, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32))
ALT(DEF_ASM_OP1(pushw, 0x50, 0, OPC_REG | OPC_WL, OPT_REGW))
ALT(DEF_ASM_OP1(pushw, 0xff, 6, OPC_MODRM | OPC_WL, OPT_REGW | OPT_EA))
+ALT(DEF_ASM_OP1(pushw, 0x6a, 0, OPC_WL, OPT_IM8S))
ALT(DEF_ASM_OP1(pushw, 0x68, 0, OPC_WL, OPT_IM32))
ALT(DEF_ASM_OP1(pushw, 0x06, 0, OPC_WL, OPT_SEG))
- DEF_ASM_OP1(pushb, 0x6a, 0, OPC_B, OPT_IM8S)
ALT(DEF_ASM_OP1(popw, 0x58, 0, OPC_REG | OPC_WL, OPT_REGW))
ALT(DEF_ASM_OP1(popw, 0x8f, 0, OPC_MODRM | OPC_WL, OPT_REGW | OPT_EA))
@@ -203,7 +206,9 @@ ALT(DEF_ASM_OP1(call, 0xff, 2, OPC_MODRM, OPT_INDIR))
ALT(DEF_ASM_OP1(call, 0xe8, 0, OPC_JMP, OPT_ADDR))
ALT(DEF_ASM_OP1(jmp, 0xff, 4, OPC_MODRM, OPT_INDIR))
ALT(DEF_ASM_OP1(jmp, 0xeb, 0, OPC_SHORTJMP | OPC_JMP, OPT_ADDR))
+#ifdef I386_ASM_16
ALT(DEF_ASM_OP1(jmp, 0xff, 0, OPC_JMP | OPC_WL, OPT_REGW))
+#endif
ALT(DEF_ASM_OP2(lcall, 0x9a, 0, 0, OPT_IM16, OPT_IM32))
ALT(DEF_ASM_OP1(lcall, 0xff, 3, 0, OPT_EA))
@@ -353,8 +358,10 @@ ALT(DEF_ASM_OP2(lslw, 0x0f03, 0, OPC_MODRM | OPC_WL, OPT_EA | OPT_REG, OPT_REG))
DEF_ASM_OP1(verr, 0x0f00, 4, OPC_MODRM, OPT_REG | OPT_EA)
DEF_ASM_OP1(verw, 0x0f00, 5, OPC_MODRM, OPT_REG | OPT_EA)
+#ifdef I386_ASM_16
/* 386 */
DEF_ASM_OP0(loadall386, 0x0f07)
+#endif
/* 486 */
DEF_ASM_OP1(bswap, 0x0fc8, 0, OPC_REG, OPT_REG32 )
@@ -369,7 +376,8 @@ ALT(DEF_ASM_OP2(cmpxchgb, 0x0fb0, 0, OPC_MODRM | OPC_BWL, OPT_REG, OPT_REG | OPT
DEF_ASM_OP1(cmpxchg8b, 0x0fc7, 1, OPC_MODRM, OPT_EA )
/* pentium pro */
-ALT(DEF_ASM_OP2(cmovo, 0x0f40, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
+ ALT(DEF_ASM_OP2(cmovo, 0x0f40, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
+#ifdef I386_ASM_16
ALT(DEF_ASM_OP2(cmovno, 0x0f41, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
ALT(DEF_ASM_OP2(cmovc, 0x0f42, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
ALT(DEF_ASM_OP2(cmovnc, 0x0f43, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
@@ -377,7 +385,7 @@ ALT(DEF_ASM_OP2(cmovz, 0x0f44, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_
ALT(DEF_ASM_OP2(cmovnz, 0x0f45, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
ALT(DEF_ASM_OP2(cmovna, 0x0f46, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
ALT(DEF_ASM_OP2(cmova, 0x0f47, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
-
+#endif
DEF_ASM_OP2(fcmovb, 0xdac0, 0, OPC_REG, OPT_ST, OPT_ST0 )
DEF_ASM_OP2(fcmove, 0xdac8, 0, OPC_REG, OPT_ST, OPT_ST0 )
DEF_ASM_OP2(fcmovbe, 0xdad0, 0, OPC_REG, OPT_ST, OPT_ST0 )
@@ -394,6 +402,7 @@ ALT(DEF_ASM_OP2(cmova, 0x0f47, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_
/* mmx */
DEF_ASM_OP0(emms, 0x0f77) /* must be last OP0 */
+
DEF_ASM_OP2(movd, 0x0f6e, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_MMX )
ALT(DEF_ASM_OP2(movd, 0x0f7e, 0, OPC_MODRM, OPT_MMX, OPT_EA | OPT_REG32 ))
DEF_ASM_OP2(movq, 0x0f6f, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
diff --git a/i386-gen.c b/i386-gen.c
index d44737a..93af341 100644
--- a/i386-gen.c
+++ b/i386-gen.c
@@ -109,6 +109,12 @@ void o(unsigned int c)
}
}
+void gen_le16(int v)
+{
+ g(v);
+ g(v >> 8);
+}
+
void gen_le32(int c)
{
g(c);
@@ -161,6 +167,13 @@ static void gen_addr32(int r, Sym *sym, int c)
gen_le32(c);
}
+static void gen_addrpc32(int r, Sym *sym, int c)
+{
+ if (r & VT_SYM)
+ greloc(cur_text_section, sym, ind, R_386_PC32);
+ gen_le32(c - 4);
+}
+
/* generate a modrm reference. 'op_reg' contains the addtionnal 3
opcode bits */
static void gen_modrm(int op_reg, int r, Sym *sym, int c)
diff --git a/i386-tok.h b/i386-tok.h
index fc47fce..d1e4bf3 100644
--- a/i386-tok.h
+++ b/i386-tok.h
@@ -1,5 +1,7 @@
-
+/* ------------------------------------------------------------------ */
/* WARNING: relative order of tokens is important. */
+
+/* register */
DEF_ASM(al)
DEF_ASM(cl)
DEF_ASM(dl)
@@ -24,6 +26,16 @@
DEF_ASM(ebp)
DEF_ASM(esi)
DEF_ASM(edi)
+#ifdef TCC_TARGET_X86_64
+ DEF_ASM(rax)
+ DEF_ASM(rcx)
+ DEF_ASM(rdx)
+ DEF_ASM(rbx)
+ DEF_ASM(rsp)
+ DEF_ASM(rbp)
+ DEF_ASM(rsi)
+ DEF_ASM(rdi)
+#endif
DEF_ASM(mm0)
DEF_ASM(mm1)
DEF_ASM(mm2)
@@ -80,39 +92,39 @@
DEF_ASM(gs)
DEF_ASM(st)
- DEF_BWL(mov)
-
/* generic two operands */
- DEF_BWL(add)
- DEF_BWL(or)
- DEF_BWL(adc)
- DEF_BWL(sbb)
- DEF_BWL(and)
- DEF_BWL(sub)
- DEF_BWL(xor)
- DEF_BWL(cmp)
+ DEF_BWLX(mov)
+
+ DEF_BWLX(add)
+ DEF_BWLX(or)
+ DEF_BWLX(adc)
+ DEF_BWLX(sbb)
+ DEF_BWLX(and)
+ DEF_BWLX(sub)
+ DEF_BWLX(xor)
+ DEF_BWLX(cmp)
/* unary ops */
- DEF_BWL(inc)
- DEF_BWL(dec)
- DEF_BWL(not)
- DEF_BWL(neg)
- DEF_BWL(mul)
- DEF_BWL(imul)
- DEF_BWL(div)
- DEF_BWL(idiv)
+ DEF_BWLX(inc)
+ DEF_BWLX(dec)
+ DEF_BWLX(not)
+ DEF_BWLX(neg)
+ DEF_BWLX(mul)
+ DEF_BWLX(imul)
+ DEF_BWLX(div)
+ DEF_BWLX(idiv)
- DEF_BWL(xchg)
- DEF_BWL(test)
+ DEF_BWLX(xchg)
+ DEF_BWLX(test)
/* shifts */
- DEF_BWL(rol)
- DEF_BWL(ror)
- DEF_BWL(rcl)
- DEF_BWL(rcr)
- DEF_BWL(shl)
- DEF_BWL(shr)
- DEF_BWL(sar)
+ DEF_BWLX(rol)
+ DEF_BWLX(ror)
+ DEF_BWLX(rcl)
+ DEF_BWLX(rcr)
+ DEF_BWLX(shl)
+ DEF_BWLX(shr)
+ DEF_BWLX(sar)
DEF_ASM(shldw)
DEF_ASM(shldl)
@@ -123,21 +135,31 @@
DEF_ASM(pushw)
DEF_ASM(pushl)
+#ifdef TCC_TARGET_X86_64
+ DEF_ASM(pushq)
+#endif
DEF_ASM(push)
+
DEF_ASM(popw)
DEF_ASM(popl)
+#ifdef TCC_TARGET_X86_64
+ DEF_ASM(popq)
+#endif
DEF_ASM(pop)
+
DEF_BWL(in)
DEF_BWL(out)
DEF_WL(movzb)
-
DEF_ASM(movzwl)
DEF_ASM(movsbw)
DEF_ASM(movsbl)
DEF_ASM(movswl)
+#ifdef TCC_TARGET_X86_64
+ DEF_ASM(movslq)
+#endif
- DEF_WL(lea)
+ DEF_WLX(lea)
DEF_ASM(les)
DEF_ASM(lds)
@@ -155,14 +177,14 @@
DEF_ASMTEST(set)
DEF_ASMTEST(cmov)
- DEF_WL(bsf)
- DEF_WL(bsr)
- DEF_WL(bt)
- DEF_WL(bts)
- DEF_WL(btr)
- DEF_WL(btc)
+ DEF_WLX(bsf)
+ DEF_WLX(bsr)
+ DEF_WLX(bt)
+ DEF_WLX(bts)
+ DEF_WLX(btr)
+ DEF_WLX(btc)
- DEF_WL(lsl)
+ DEF_WLX(lsl)
/* generic FP ops */
DEF_FP(add)
@@ -178,32 +200,35 @@
DEF_FP(div)
DEF_FP(divr)
- DEF_BWL(xadd)
- DEF_BWL(cmpxchg)
+ DEF_BWLX(xadd)
+ DEF_BWLX(cmpxchg)
/* string ops */
- DEF_BWL(cmps)
- DEF_BWL(scmp)
+ DEF_BWLX(cmps)
+ DEF_BWLX(scmp)
DEF_BWL(ins)
DEF_BWL(outs)
- DEF_BWL(lods)
- DEF_BWL(slod)
- DEF_BWL(movs)
- DEF_BWL(smov)
- DEF_BWL(scas)
- DEF_BWL(ssca)
- DEF_BWL(stos)
- DEF_BWL(ssto)
+ DEF_BWLX(lods)
+ DEF_BWLX(slod)
+ DEF_BWLX(movs)
+ DEF_BWLX(smov)
+ DEF_BWLX(scas)
+ DEF_BWLX(ssca)
+ DEF_BWLX(stos)
+ DEF_BWLX(ssto)
/* generic asm ops */
-
#define ALT(x)
#define DEF_ASM_OP0(name, opcode) DEF_ASM(name)
#define DEF_ASM_OP0L(name, opcode, group, instr_type)
#define DEF_ASM_OP1(name, opcode, group, instr_type, op0)
#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1)
#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2)
-#include "i386-asm.h"
+#ifdef TCC_TARGET_X86_64
+# include "x86_64-asm.h"
+#else
+# include "i386-asm.h"
+#endif
#define ALT(x)
#define DEF_ASM_OP0(name, opcode)
@@ -211,4 +236,8 @@
#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) DEF_ASM(name)
#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) DEF_ASM(name)
#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) DEF_ASM(name)
-#include "i386-asm.h"
+#ifdef TCC_TARGET_X86_64
+# include "x86_64-asm.h"
+#else
+# include "i386-asm.h"
+#endif
diff --git a/libtcc.c b/libtcc.c
index 40b845e..823078e 100644
--- a/libtcc.c
+++ b/libtcc.c
@@ -325,14 +325,10 @@ static inline int toup(int c)
#ifdef CONFIG_TCC_ASM
-#ifdef TCC_TARGET_I386
+#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
#include "i386-asm.c"
#endif
-#ifdef TCC_TARGET_X86_64
-#include "x86_64-asm.c"
-#endif
-
#include "tccasm.c"
#else
static void asm_instr(void)
@@ -854,10 +850,14 @@ static void put_extern_sym(Sym *sym, Section *section,
/* add a new relocation entry to symbol 'sym' in section 's' */
static void greloc(Section *s, Sym *sym, unsigned long offset, int type)
{
- if (!sym->c)
- put_extern_sym(sym, NULL, 0, 0);
+ int c = 0;
+ if (sym) {
+ if (0 == sym->c)
+ put_extern_sym(sym, NULL, 0, 0);
+ c = sym->c;
+ }
/* now we can add ELF relocation info */
- put_elf_reloc(symtab_section, s, offset, type, sym->c);
+ put_elf_reloc(symtab_section, s, offset, type, c);
}
static void strcat_vprintf(char *buf, int buf_size, const char *fmt, va_list ap)
diff --git a/tcc.h b/tcc.h
index a96a893..430eb79 100644
--- a/tcc.h
+++ b/tcc.h
@@ -660,35 +660,41 @@ struct TCCState {
/* all identificators and strings have token above that */
#define TOK_IDENT 256
-/* only used for i386 asm opcodes definitions */
#define DEF_ASM(x) DEF(TOK_ASM_ ## x, #x)
+#define TOK_ASM_int TOK_INT
+#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
+/* only used for i386 asm opcodes definitions */
#define DEF_BWL(x) \
DEF(TOK_ASM_ ## x ## b, #x "b") \
DEF(TOK_ASM_ ## x ## w, #x "w") \
DEF(TOK_ASM_ ## x ## l, #x "l") \
DEF(TOK_ASM_ ## x, #x)
-
#define DEF_WL(x) \
DEF(TOK_ASM_ ## x ## w, #x "w") \
DEF(TOK_ASM_ ## x ## l, #x "l") \
DEF(TOK_ASM_ ## x, #x)
-
#ifdef TCC_TARGET_X86_64
-
-#define DEF_BWLQ(x) \
+# define DEF_BWLQ(x) \
DEF(TOK_ASM_ ## x ## b, #x "b") \
DEF(TOK_ASM_ ## x ## w, #x "w") \
DEF(TOK_ASM_ ## x ## l, #x "l") \
DEF(TOK_ASM_ ## x ## q, #x "q") \
DEF(TOK_ASM_ ## x, #x)
-
-#define DEF_WLQ(x) \
+# define DEF_WLQ(x) \
DEF(TOK_ASM_ ## x ## w, #x "w") \
DEF(TOK_ASM_ ## x ## l, #x "l") \
DEF(TOK_ASM_ ## x ## q, #x "q") \
DEF(TOK_ASM_ ## x, #x)
-
+# define DEF_BWLX DEF_BWLQ
+# define DEF_WLX DEF_WLQ
+/* number of sizes + 1 */
+# define NBWLX 5
+#else
+# define DEF_BWLX DEF_BWL
+# define DEF_WLX DEF_WL
+/* number of sizes + 1 */
+# define NBWLX 4
#endif
#define DEF_FP1(x) \
@@ -734,7 +740,7 @@ struct TCCState {
DEF_ASM(x ## nle) \
DEF_ASM(x ## g)
-#define TOK_ASM_int TOK_INT
+#endif // defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
enum tcc_token {
TOK_LAST = TOK_IDENT - 1,
diff --git a/tcctok.h b/tcctok.h
index 5ad5cf5..c214ace 100644
--- a/tcctok.h
+++ b/tcctok.h
@@ -233,7 +233,6 @@
#endif
/* Tiny Assembler */
-
DEF_ASM(byte)
DEF_ASM(word)
DEF_ASM(align)
@@ -258,9 +257,6 @@
DEF_ASM(code64)
#endif
-#ifdef TCC_TARGET_I386
+#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
#include "i386-tok.h"
-#elif TCC_TARGET_X86_64
-#include "x86_64-tok.h"
#endif
-
diff --git a/win32/build-tcc.bat b/win32/build-tcc.bat
index 5226d7a..b706db4 100644
--- a/win32/build-tcc.bat
+++ b/win32/build-tcc.bat
@@ -3,8 +3,6 @@
@rem ----------------------------------------------------
@set PROMPT=$G$S
-copy ..\include\*.h include
-
echo>..\config.h #define TCC_VERSION "0.9.25"
echo>>..\config.h #define TCC_TARGET_PE 1
echo>>..\config.h #define CONFIG_TCCDIR "."
@@ -27,7 +25,6 @@ echo>>..\config.h #define TCC_TARGET_X86_64 1
:libtcc
if not exist libtcc\nul mkdir libtcc
copy ..\libtcc.h libtcc\libtcc.h
-
%P%gcc -Os -fno-strict-aliasing ../libtcc.c -c -o libtcc.o
%P%ar rcs libtcc/libtcc.a libtcc.o
@@ -35,24 +32,13 @@ copy ..\libtcc.h libtcc\libtcc.h
%P%gcc -Os -fno-strict-aliasing ../tcc.c -o tcc.exe -s -DTCC_USE_LIBTCC -ltcc -Llibtcc
:libtcc1.a
+copy ..\include\*.h include
.\tcc -c lib/crt1.c
.\tcc -c lib/wincrt1.c
.\tcc -c lib/dllcrt1.c
.\tcc -c lib/dllmain.c
.\tcc -c ../lib/libtcc1.c
-@rem if not x%P%==x goto use_yasm
.\tcc -c lib/chkstk.S
.\tcc -c ../lib/alloca86%S%.S
tiny_libmaker lib/libtcc1.a crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o libtcc1.o alloca86%S%.o
-@goto cleanup
-
-:use_yasm
-.\tcc -o tmp.s -E lib/chkstk.S
-yasm -p gnu -f elf64 -o chkstk.o tmp.s
-.\tcc -o tmp.s -E ../lib/alloca86_64.S
-yasm -p gnu -f elf64 -o alloca86_64.o tmp.s
-del tmp.s
-tiny_libmaker lib/libtcc1.a crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o libtcc1.o alloca86_64.o
-
-:cleanup
del *.o
diff --git a/x86_64-asm.c b/x86_64-asm.c
deleted file mode 100644
index 2a894f8..0000000
--- a/x86_64-asm.c
+++ /dev/null
@@ -1,1266 +0,0 @@
-/*
- * x86_64 specific functions for TCC assembler
- *
- * Copyright (c) 2009 FrĂŠdĂŠric Feret
- *
- * Based on i386-asm.c by Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#define MAX_OPERANDS 3
-
-typedef struct ASMInstr {
- uint16_t sym;
- uint16_t opcode;
- uint16_t instr_type;
-#define OPC_JMP 0x01 /* jmp operand */
-#define OPC_B 0x02 /* only used zith OPC_WL */
-#define OPC_WL 0x04 /* accepts w, l or no suffix */
-#define OPC_BWL (OPC_B | OPC_WL) /* accepts b, w, l or no suffix */
-#define OPC_REG 0x08 /* register is added to opcode */
-#define OPC_MODRM 0x10 /* modrm encoding */
-#define OPC_FWAIT 0x20 /* add fwait opcode */
-#define OPC_TEST 0x40 /* test opcodes */
-#define OPC_SHIFT 0x80 /* shift opcodes */
-#define OPC_D16 0x0100 /* generate data16 prefix */
-#define OPC_ARITH 0x0200 /* arithmetic opcodes */
-#define OPC_SHORTJMP 0x0400 /* short jmp operand */
-#define OPC_FARITH 0x0800 /* FPU arithmetic opcodes */
-#define OPC_WLQ 0x1000 /* accepts w, l, q or no suffix */
-#define OPC_BWLQ (OPC_B | OPC_WLQ) /* accepts b, w, l, q or no suffix */
-#define OPC_GROUP_SHIFT 13
-
-/* in order to compress the operand type, we use specific operands and
- we or only with EA */
-#define OPT_REG8 0 /* warning: value is hardcoded from TOK_ASM_xxx */
-#define OPT_REG16 1 /* warning: value is hardcoded from TOK_ASM_xxx */
-#define OPT_REG32 2 /* warning: value is hardcoded from TOK_ASM_xxx */
-#define OPT_REG64 3
-#define OPT_MMX 4 /* warning: value is hardcoded from TOK_ASM_xxx */
-#define OPT_SSE 5 /* warning: value is hardcoded from TOK_ASM_xxx */
-#define OPT_CR 6 /* warning: value is hardcoded from TOK_ASM_xxx */
-#define OPT_TR 7 /* warning: value is hardcoded from TOK_ASM_xxx */
-#define OPT_DB 8 /* warning: value is hardcoded from TOK_ASM_xxx */
-#define OPT_SEG 9
-#define OPT_ST 10
-#define OPT_IM8 11
-#define OPT_IM8S 12
-#define OPT_IM16 13
-#define OPT_IM32 14
-#define OPT_IM64 15
-#define OPT_EAX 16 /* %al, %ax, %eax or %rax register */
-#define OPT_ST0 17 /* %st(0) register */
-#define OPT_CL 18 /* %cl register */
-#define OPT_DX 19 /* %dx register */
-#define OPT_ADDR 20 /* OP_EA with only offset */
-#define OPT_INDIR 21 /* *(expr) */
-
-/* composite types */
-#define OPT_COMPOSITE_FIRST 22
-#define OPT_IM 23 /* IM8 | IM16 | IM32 | IM64 */
-#define OPT_REG 24 /* REG8 | REG16 | REG32 | REG64 */
-#define OPT_REGW 25 /* REG16 | REG32 | REG64 */
-#define OPT_IMW 26 /* IM16 | IM32 | IM64 */
-#define OPT_IMNO64 27 /* IM16 | IM32 */
-
-/* can be ored with any OPT_xxx */
-#define OPT_EA 0x80
-
- uint8_t nb_ops;
- uint8_t op_type[MAX_OPERANDS]; /* see OP_xxx */
-} ASMInstr;
-
-typedef struct Operand {
- uint32_t type;
-#define OP_REG8 (1 << OPT_REG8)
-#define OP_REG16 (1 << OPT_REG16)
-#define OP_REG32 (1 << OPT_REG32)
-#define OP_MMX (1 << OPT_MMX)
-#define OP_SSE (1 << OPT_SSE)
-#define OP_CR (1 << OPT_CR)
-#define OP_TR (1 << OPT_TR)
-#define OP_DB (1 << OPT_DB)
-#define OP_SEG (1 << OPT_SEG)
-#define OP_ST (1 << OPT_ST)
-#define OP_IM8 (1 << OPT_IM8)
-#define OP_IM8S (1 << OPT_IM8S)
-#define OP_IM16 (1 << OPT_IM16)
-#define OP_IM32 (1 << OPT_IM32)
-#define OP_EAX (1 << OPT_EAX)
-#define OP_ST0 (1 << OPT_ST0)
-#define OP_CL (1 << OPT_CL)
-#define OP_DX (1 << OPT_DX)
-#define OP_ADDR (1 << OPT_ADDR)
-#define OP_INDIR (1 << OPT_INDIR)
-#define OP_REG64 (1 << OPT_REG64)
-#define OP_IM64 (1 << OPT_IM64)
-
-#define OP_EA 0x40000000
-#define OP_REG (OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64)
-#define OP_IM OP_IM64
- int8_t reg; /* register, -1 if none */
- int8_t reg2; /* second register, -1 if none */
- uint8_t shift;
- ExprValue e;
-} Operand;
-
-static const uint8_t reg_to_size[9] = {
-/*
- [OP_REG8] = 0,
- [OP_REG16] = 1,
- [OP_REG32] = 2,
- [OP_REG64] = 3,
-*/
- 0, 0, 1, 0, 2, 0, 0, 0, 3
-};
-
-#define NB_TEST_OPCODES 30
-
-static const uint8_t test_bits[NB_TEST_OPCODES] = {
- 0x00, /* o */
- 0x01, /* no */
- 0x02, /* b */
- 0x02, /* c */
- 0x02, /* nae */
- 0x03, /* nb */
- 0x03, /* nc */
- 0x03, /* ae */
- 0x04, /* e */
- 0x04, /* z */
- 0x05, /* ne */
- 0x05, /* nz */
- 0x06, /* be */
- 0x06, /* na */
- 0x07, /* nbe */
- 0x07, /* a */
- 0x08, /* s */
- 0x09, /* ns */
- 0x0a, /* p */
- 0x0a, /* pe */
- 0x0b, /* np */
- 0x0b, /* po */
- 0x0c, /* l */
- 0x0c, /* nge */
- 0x0d, /* nl */
- 0x0d, /* ge */
- 0x0e, /* le */
- 0x0e, /* ng */
- 0x0f, /* nle */
- 0x0f, /* g */
-};
-
-static const uint8_t segment_prefixes[] = {
- 0x26, /* es */
- 0x2e, /* cs */
- 0x36, /* ss */
- 0x3e, /* ds */
- 0x64, /* fs */
- 0x65 /* gs */
-};
-
-static const ASMInstr asm_instrs[] = {
-#define ALT(x) x
-#define DEF_ASM_OP0(name, opcode)
-#define DEF_ASM_OP0L(name, opcode, group, instr_type) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 0 },
-#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 1, { op0 }},
-#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 2, { op0, op1 }},
-#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 3, { op0, op1, op2 }},
-#include "x86_64-asm.h"
-
- /* last operation */
- { 0, },
-};
-
-static const uint16_t op0_codes[] = {
-#define ALT(x)
-#define DEF_ASM_OP0(x, opcode) opcode,
-#define DEF_ASM_OP0L(name, opcode, group, instr_type)
-#define DEF_ASM_OP1(name, opcode, group, instr_type, op0)
-#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1)
-#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2)
-#include "x86_64-asm.h"
-};
-
-static inline int get_reg_shift(TCCState *s1)
-{
- int shift, v;
-
- v = asm_int_expr(s1);
- switch(v) {
- case 1:
- shift = 0;
- break;
- case 2:
- shift = 1;
- break;
- case 4:
- shift = 2;
- break;
- case 8:
- shift = 3;
- break;
- default:
- expect("1, 2, 4 or 8 constant");
- shift = 0;
- break;
- }
- return shift;
-}
-
-static int asm_parse_reg(void)
-{
- int reg;
- if (tok != '%')
- goto error_32;
- next();
- if (tok >= TOK_ASM_rax && tok <= TOK_ASM_rdi) {
- reg = tok - TOK_ASM_rax;
- next();
- return reg;
- } else if (tok >= TOK_ASM_eax && tok <= TOK_ASM_edi) {
- reg = tok - TOK_ASM_eax;
- next();
- return reg;
- } else {
- error_32:
- expect("64 bit register");
- return 0;
- }
-}
-
-static void parse_operand(TCCState *s1, Operand *op)
-{
- ExprValue e;
- int reg, indir;
- const char *p;
-
- indir = 0;
- if (tok == '*') {
- next();
- indir = OP_INDIR;
- }
-
- if (tok == '%') {
- next();
- if (tok >= TOK_ASM_al && tok <= TOK_ASM_db7) {
- reg = tok - TOK_ASM_al;
- op->type = 1 << (reg >> 3); /* WARNING: do not change constant order */
- op->reg = reg & 7;
- if ((op->type & OP_REG) && op->reg == TREG_RAX)
- op->type |= OP_EAX;
- else if (op->type == OP_REG8 && op->reg == TREG_RCX)
- op->type |= OP_CL;
- else if (op->type == OP_REG16 && op->reg == TREG_RDX)
- op->type |= OP_DX;
- } else if (tok >= TOK_ASM_dr0 && tok <= TOK_ASM_dr7) {
- op->type = OP_DB;
- op->reg = tok - TOK_ASM_dr0;
- } else if (tok >= TOK_ASM_es && tok <= TOK_ASM_gs) {
- op->type = OP_SEG;
- op->reg = tok - TOK_ASM_es;
- } else if (tok == TOK_ASM_st) {
- op->type = OP_ST;
- op->reg = 0;
- next();
- if (tok == '(') {
- next();
- if (tok != TOK_PPNUM)
- goto reg_error;
- p = tokc.cstr->data;
- reg = p[0] - '0';
- if ((unsigned)reg >= 8 || p[1] != '\0')
- goto reg_error;
- op->reg = reg;
- next();
- skip(')');
- }
- if (op->reg == 0)
- op->type |= OP_ST0;
- goto no_skip;
- } else {
- reg_error:
- error("unknown register");
- }
- next();
- no_skip: ;
- } else if (tok == '$') {
- /* constant value */
- next();
- asm_expr(s1, &e);
- op->type = OP_IM64;
- op->e.v = e.v;
- op->e.sym = e.sym;
- if (!op->e.sym) {
- if (op->e.v == (uint8_t)op->e.v)
- op->type |= OP_IM8;
- if (op->e.v == (int8_t)op->e.v)
- op->type |= OP_IM8S;
- if (op->e.v == (uint16_t)op->e.v)
- op->type |= OP_IM16;
- if (op->e.v == (uint32_t)op->e.v)
- op->type |= OP_IM32;
- }
- } else {
- /* address(reg,reg2,shift) with all variants */
- op->type = OP_EA;
- op->reg = -1;
- op->reg2 = -1;
- op->shift = 0;
- if (tok != '(') {
- asm_expr(s1, &e);
- op->e.v = e.v;
- op->e.sym = e.sym;
- } else {
- op->e.v = 0;
- op->e.sym = NULL;
- }
- if (tok == '(') {
- next();
- if (tok != ',') {
- op->reg = asm_parse_reg();
- }
- if (tok == ',') {
- next();
- if (tok != ',') {
- op->reg2 = asm_parse_reg();
- }
- if (tok == ',') {
- next();
- op->shift = get_reg_shift(s1);
- }
- }
- skip(')');
- }
- if (op->reg == -1 && op->reg2 == -1)
- op->type |= OP_ADDR;
- }
- op->type |= indir;
-}
-
-/* XXX: unify with C code output ? */
-static void gen_expr32(ExprValue *pe)
-{
- if (pe->sym)
- greloc(cur_text_section, pe->sym, ind, R_X86_64_32);
- gen_le32(pe->v);
-}
-
-static void gen_expr64(ExprValue *pe)
-{
- if (pe->sym)
- greloc(cur_text_section, pe->sym, ind, R_X86_64_64);
- gen_le64(pe->v);
-}
-
-/* XXX: unify with C code output ? */
-static void gen_disp32(ExprValue *pe)
-{
- Sym *sym;
- sym = pe->sym;
- if (sym) {
- if (sym->r == cur_text_section->sh_num) {
- /* same section: we can output an absolute value. Note
- that the TCC compiler behaves differently here because
- it always outputs a relocation to ease (future) code
- elimination in the linker */
- gen_le32(pe->v + sym->jnext - ind - 4);
- } else {
- greloc(cur_text_section, sym, ind, R_X86_64_PC32);
- gen_le32(pe->v - 4);
- }
- } else {
- /* put an empty PC32 relocation */
- put_elf_reloc(symtab_section, cur_text_section,
- ind, R_X86_64_PC32, 0);
- gen_le32(pe->v - 4);
- }
-}
-
-
-static void gen_le16(int v)
-{
- g(v);
- g(v >> 8);
-}
-
-/* generate the modrm operand */
-static inline void asm_modrm(int reg, Operand *op)
-{
- int mod, reg1, reg2, sib_reg1;
-
- if (op->type & (OP_REG | OP_MMX | OP_SSE)) {
- g(0xc0 + (reg << 3) + op->reg);
- } else if (op->reg == -1 && op->reg2 == -1) {
- /* displacement only */
- g(0x05 + (reg << 3));
- gen_expr32(&op->e);
- } else {
- sib_reg1 = op->reg;
- /* fist compute displacement encoding */
- if (sib_reg1 == -1) {
- sib_reg1 = 5;
- mod = 0x00;
- } else if (op->e.v == 0 && !op->e.sym && op->reg != 5) {
- mod = 0x00;
- } else if (op->e.v == (int8_t)op->e.v && !op->e.sym) {
- mod = 0x40;
- } else {
- mod = 0x80;
- }
- /* compute if sib byte needed */
- reg1 = op->reg;
- if (op->reg2 != -1)
- reg1 = 4;
- g(mod + (reg << 3) + reg1);
- if (reg1 == 4) {
- /* add sib byte */
- reg2 = op->reg2;
- if (reg2 == -1)
- reg2 = 4; /* indicate no index */
- g((op->shift << 6) + (reg2 << 3) + sib_reg1);
- }
-
- /* add offset */
- if (mod == 0x40) {
- g(op->e.v);
- } else if (mod == 0x80 || op->reg == -1) {
- gen_expr32(&op->e);
- }
- }
-}
-
-static void asm_opcode(TCCState *s1, int opcode)
-{
- const ASMInstr *pa;
- int i, modrm_index, reg, v, op1, is_short_jmp, seg_prefix;
- int nb_ops, s, ss;
- Operand ops[MAX_OPERANDS], *pop;
- int op_type[3]; /* decoded op type */
- char rex;
-
- /* get operands */
- pop = ops;
- nb_ops = 0;
- seg_prefix = 0;
- rex = 0x48;
- for(;;) {
- if (tok == ';' || tok == TOK_LINEFEED)
- break;
- if (nb_ops >= MAX_OPERANDS) {
- error("incorrect number of operands");
- }
- parse_operand(s1, pop);
- if (tok == ':') {
- if (pop->type != OP_SEG || seg_prefix) {
- error("incorrect prefix");
- }
- seg_prefix = segment_prefixes[pop->reg];
- next();
- parse_operand(s1, pop);
- if (!(pop->type & OP_EA)) {
- error("segment prefix must be followed by memory reference");
- }
- }
- pop++;
- nb_ops++;
- if (tok != ',')
- break;
- next();
- }
-
- is_short_jmp = 0;
- s = 0; /* avoid warning */
-
- /* optimize matching by using a lookup table (no hashing is needed
- !) */
- for(pa = asm_instrs; pa->sym != 0; pa++) {
- s = 0;
- if (pa->instr_type & OPC_FARITH) {
- v = opcode - pa->sym;
- if (!((unsigned)v < 8 * 6 && (v % 6) == 0))
- continue;
- } else if (pa->instr_type & OPC_ARITH) {
- if (!(opcode >= pa->sym && opcode < pa->sym + 8 * 5))
- continue;
- s = (opcode - pa->sym) % 5;
- } else if (pa->instr_type & OPC_SHIFT) {
- if (!(opcode >= pa->sym && opcode < pa->sym + 7 * 5))
- continue;
- s = (opcode - pa->sym) % 5;
- } else if (pa->instr_type & OPC_TEST) {
- if (!(opcode >= pa->sym && opcode < pa->sym + NB_TEST_OPCODES))
- continue;
- } else if (pa->instr_type & OPC_B) {
- if (!(opcode >= pa->sym && opcode < pa->sym + 5))
- continue;
- s = opcode - pa->sym;
- } else if (pa->instr_type & OPC_WLQ) {
- if (!(opcode >= pa->sym && opcode < pa->sym + 4))
- continue;
- s = opcode - pa->sym + 1;
- } else {
- if (pa->sym != opcode)
- continue;
- }
- if (pa->nb_ops != nb_ops)
- continue;
- /* now decode and check each operand */
- for(i = 0; i < nb_ops; i++) {
- int op1, op2;
- op1 = pa->op_type[i];
- op2 = op1 & 0x1f;
- switch(op2) {
- case OPT_IM:
- v = OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64;
- break;
- case OPT_REG:
- v = OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64;
- break;
- case OPT_REGW:
- v = OP_REG16 | OP_REG32 | OP_REG64;
- break;
- case OPT_IMW:
- v = OP_IM16 | OP_IM32 | OP_IM64;
- break;
- case OPT_IMNO64:
- v = OP_IM16 | OP_IM32;
- break;
- default:
- v = 1 << op2;
- break;
- }
- if (op1 & OPT_EA)
- v |= OP_EA;
- op_type[i] = v;
- if ((ops[i].type & v) == 0)
- goto next;
- }
- /* all is matching ! */
- break;
- next: ;
- }
- if (pa->sym == 0) {
- if (opcode >= TOK_ASM_clc && opcode <= TOK_ASM_emms) {
- int b;
- b = op0_codes[opcode - TOK_ASM_clc];
- if (b & 0xff00)
- g(b >> 8);
- g(b);
- return;
- } else {
- error("unknown opcode '%s'",
- get_tok_str(opcode, NULL));
- }
- }
- /* if the size is unknown, then evaluate it (OPC_B or OPC_WL case) */
- if (s == 4) {
- for(i = 0; s == 4 && i < nb_ops; i++) {
- if ((ops[i].type & OP_REG) && !(op_type[i] & (OP_CL | OP_DX)))
- s = reg_to_size[ops[i].type & OP_REG];
- }
- if (s == 4) {
- if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) &&
- (ops[0].type & (OP_SEG | OP_IM8S | OP_IM32 | OP_IM64)))
- s = 2;
- else
- error("cannot infer opcode suffix");
- }
- }
-
- /* generate data16 prefix if needed */
- ss = s;
- if (s == 1 || (pa->instr_type & OPC_D16))
- g(0x66);
- else if (s == 2)
- s = 1;
- else if (s == 3) {
- /* generate REX prefix */
- if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) &&
- (ops[0].type & OP_REG64))
- ;
- else
- g(rex);
- s = 1;
- }
- /* now generates the operation */
- if (pa->instr_type & OPC_FWAIT)
- g(0x9b);
- if (seg_prefix)
- g(seg_prefix);
-
- v = pa->opcode;
- if (v == 0x69 || v == 0x69) {
- /* kludge for imul $im, %reg */
- nb_ops = 3;
- ops[2] = ops[1];
- } else if (v == 0xcd && ops[0].e.v == 3 && !ops[0].e.sym) {
- v--; /* int $3 case */
- nb_ops = 0;
- } else if ((v == 0x06 || v == 0x07)) {
- if (ops[0].reg >= 4) {
- /* push/pop %fs or %gs */
- v = 0x0fa0 + (v - 0x06) + ((ops[0].reg - 4) << 3);
- } else {
- v += ops[0].reg << 3;
- }
- nb_ops = 0;
- } else if (v <= 0x05) {
- /* arith case */
- v += ((opcode - TOK_ASM_addb) / 5) << 3;
- } else if ((pa->instr_type & (OPC_FARITH | OPC_MODRM)) == OPC_FARITH) {
- /* fpu arith case */
- v += ((opcode - pa->sym) / 6) << 3;
- }
- if (pa->instr_type & OPC_REG) {
- for(i = 0; i < nb_ops; i++) {
- if (op_type[i] & (OP_REG | OP_ST)) {
- v += ops[i].reg;
- break;
- }
- }
- /* mov $im, %reg case */
- if (pa->opcode == 0xb0 && s >= 1)
- v += 7;
- }
- if (pa->instr_type & OPC_B)
- v += s;
- if (pa->instr_type & OPC_TEST)
- v += test_bits[opcode - pa->sym];
- if (pa->instr_type & OPC_SHORTJMP) {
- Sym *sym;
- int jmp_disp;
-
- /* see if we can really generate the jump with a byte offset */
- sym = ops[0].e.sym;
- if (!sym)
- goto no_short_jump;
- if (sym->r != cur_text_section->sh_num)
- goto no_short_jump;
- jmp_disp = ops[0].e.v + sym->jnext - ind - 2;
- if (jmp_disp == (int8_t)jmp_disp) {
- /* OK to generate jump */
- is_short_jmp = 1;
- ops[0].e.v = jmp_disp;
- } else {
- no_short_jump:
- if (pa->instr_type & OPC_JMP) {
- /* long jump will be allowed. need to modify the
- opcode slightly */
- if (v == 0xeb)
- v = 0xe9;
- else
- v += 0x0f10;
- } else {
- error("invalid displacement");
- }
- }
- }
- op1 = v >> 8;
- if (op1)
- g(op1);
- g(v);
-
- /* search which operand will used for modrm */
- modrm_index = 0;
- if (pa->instr_type & OPC_SHIFT) {
- reg = (opcode - pa->sym) / 5;
- if (reg == 6)
- reg = 7;
- } else if (pa->instr_type & OPC_ARITH) {
- reg = (opcode - pa->sym) / 5;
- } else if (pa->instr_type & OPC_FARITH) {
- reg = (opcode - pa->sym) / 6;
- } else {
- reg = (pa->instr_type >> OPC_GROUP_SHIFT) & 7;
- }
- if (pa->instr_type & OPC_MODRM) {
- /* first look for an ea operand */
- for(i = 0;i < nb_ops; i++) {
- if (op_type[i] & OP_EA)
- goto modrm_found;
- }
- /* then if not found, a register or indirection (shift instructions) */
- for(i = 0;i < nb_ops; i++) {
- if (op_type[i] & (OP_REG | OP_MMX | OP_SSE | OP_INDIR))
- goto modrm_found;
- }
-#ifdef ASM_DEBUG
- error("bad op table");
-#endif
- modrm_found:
- modrm_index = i;
- /* if a register is used in another operand then it is
- used instead of group */
- for(i = 0;i < nb_ops; i++) {
- v = op_type[i];
- if (i != modrm_index &&
- (v & (OP_REG | OP_MMX | OP_SSE | OP_CR | OP_TR | OP_DB | OP_SEG))) {
- reg = ops[i].reg;
- break;
- }
- }
-
- asm_modrm(reg, &ops[modrm_index]);
- }
-
- /* emit constants */
- {
- for(i = 0;i < nb_ops; i++) {
- v = op_type[i];
- if (v & (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64 | OP_IM8S | OP_ADDR)) {
- /* if multiple sizes are given it means we must look
- at the op size */
- if (v == (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64) ||
- v == (OP_IM16 | OP_IM32 | OP_IM64)) {
- if (ss == 0)
- v = OP_IM8;
- else if (ss == 1)
- v = OP_IM16;
- else if (ss == 2)
- v = OP_IM32;
- else
- v = OP_IM64;
- } else if (v == (OP_IM8 | OP_IM16 | OP_IM32) ||
- v == (OP_IM16 | OP_IM32)) {
- if (ss == 0)
- v = OP_IM8;
- else if (ss == 1)
- v = OP_IM16;
- else
- v = OP_IM32;
- }
- if (v & (OP_IM8 | OP_IM8S)) {
- if (ops[i].e.sym)
- goto error_relocate;
- g(ops[i].e.v);
- } else if (v & OP_IM16) {
- if (ops[i].e.sym) {
- error_relocate:
- error("cannot relocate");
- }
- gen_le16(ops[i].e.v);
- } else {
- if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) {
- if (is_short_jmp)
- g(ops[i].e.v);
- else
- gen_disp32(&ops[i].e);
- } else {
- if (v & OP_IM64)
- gen_expr64(&ops[i].e);
- else
- gen_expr32(&ops[i].e);
- }
- }
- } else if (v & (OP_REG32 | OP_REG64)) {
- if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) {
- /* jmp $r */
- g(0xE0 + ops[i].reg);
- }
- }
- }
- }
-}
-
-#define NB_SAVED_REGS 3
-#define NB_ASM_REGS 8
-
-/* return the constraint priority (we allocate first the lowest
- numbered constraints) */
-static inline int constraint_priority(const char *str)
-{
- int priority, c, pr;
-
- /* we take the lowest priority */
- priority = 0;
- for(;;) {
- c = *str;
- if (c == '\0')
- break;
- str++;
- switch(c) {
- case 'A':
- pr = 0;
- break;
- case 'a':
- case 'b':
- case 'c':
- case 'd':
- case 'S':
- case 'D':
- pr = 1;
- break;
- case 'q':
- pr = 2;
- break;
- case 'r':
- pr = 3;
- break;
- case 'N':
- case 'M':
- case 'I':
- case 'i':
- case 'm':
- case 'g':
- pr = 4;
- break;
- default:
- error("unknown constraint '%c'", c);
- pr = 0;
- }
- if (pr > priority)
- priority = pr;
- }
- return priority;
-}
-
-static const char *skip_constraint_modifiers(const char *p)
-{
- while (*p == '=' || *p == '&' || *p == '+' || *p == '%')
- p++;
- return p;
-}
-
-#define REG_OUT_MASK 0x01
-#define REG_IN_MASK 0x02
-
-#define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask)
-
-static void asm_compute_constraints(ASMOperand *operands,
- int nb_operands, int nb_outputs,
- const uint8_t *clobber_regs,
- int *pout_reg)
-{
- ASMOperand *op;
- int sorted_op[MAX_ASM_OPERANDS];
- int i, j, k, p1, p2, tmp, reg, c, reg_mask;
- const char *str;
- uint8_t regs_allocated[NB_ASM_REGS];
-
- /* init fields */
- for(i=0;i<nb_operands;i++) {
- op = &operands[i];
- op->input_index = -1;
- op->ref_index = -1;
- op->reg = -1;
- op->is_memory = 0;
- op->is_rw = 0;
- }
- /* compute constraint priority and evaluate references to output
- constraints if input constraints */
- for(i=0;i<nb_operands;i++) {
- op = &operands[i];
- str = op->constraint;
- str = skip_constraint_modifiers(str);
- if (isnum(*str) || *str == '[') {
- /* this is a reference to another constraint */
- k = find_constraint(operands, nb_operands, str, NULL);
- if ((unsigned)k >= i || i < nb_outputs)
- error("invalid reference in constraint %d ('%s')",
- i, str);
- op->ref_index = k;
- if (operands[k].input_index >= 0)
- error("cannot reference twice the same operand");
- operands[k].input_index = i;
- op->priority = 5;
- } else {
- op->priority = constraint_priority(str);
- }
- }
-
- /* sort operands according to their priority */
- for(i=0;i<nb_operands;i++)
- sorted_op[i] = i;
- for(i=0;i<nb_operands - 1;i++) {
- for(j=i+1;j<nb_operands;j++) {
- p1 = operands[sorted_op[i]].priority;
- p2 = operands[sorted_op[j]].priority;
- if (p2 < p1) {
- tmp = sorted_op[i];
- sorted_op[i] = sorted_op[j];
- sorted_op[j] = tmp;
- }
- }
- }
-
- for(i = 0;i < NB_ASM_REGS; i++) {
- if (clobber_regs[i])
- regs_allocated[i] = REG_IN_MASK | REG_OUT_MASK;
- else
- regs_allocated[i] = 0;
- }
- /* esp cannot be used */
- regs_allocated[4] = REG_IN_MASK | REG_OUT_MASK;
- /* ebp cannot be used yet */
- regs_allocated[5] = REG_IN_MASK | REG_OUT_MASK;
-
- /* allocate registers and generate corresponding asm moves */
- for(i=0;i<nb_operands;i++) {
- j = sorted_op[i];
- op = &operands[j];
- str = op->constraint;
- /* no need to allocate references */
- if (op->ref_index >= 0)
- continue;
- /* select if register is used for output, input or both */
- if (op->input_index >= 0) {
- reg_mask = REG_IN_MASK | REG_OUT_MASK;
- } else if (j < nb_outputs) {
- reg_mask = REG_OUT_MASK;
- } else {
- reg_mask = REG_IN_MASK;
- }
- try_next:
- c = *str++;
- switch(c) {
- case '=':
- goto try_next;
- case '+':
- op->is_rw = 1;
- /* FALL THRU */
- case '&':
- if (j >= nb_outputs)
- error("'%c' modifier can only be applied to outputs", c);
- reg_mask = REG_IN_MASK | REG_OUT_MASK;
- goto try_next;
- case 'A':
- /* allocate both eax and edx */
- if (is_reg_allocated(TREG_RAX) ||
- is_reg_allocated(TREG_RDX))
- goto try_next;
- op->is_llong = 1;
- op->reg = TREG_RAX;
- regs_allocated[TREG_RAX] |= reg_mask;
- regs_allocated[TREG_RDX] |= reg_mask;
- break;
- case 'a':
- reg = TREG_RAX;
- goto alloc_reg;
- case 'b':
- reg = 3;
- goto alloc_reg;
- case 'c':
- reg = TREG_RCX;
- goto alloc_reg;
- case 'd':
- reg = TREG_RDX;
- goto alloc_reg;
- case 'S':
- reg = 6;
- goto alloc_reg;
- case 'D':
- reg = 7;
- alloc_reg:
- if (is_reg_allocated(reg))
- goto try_next;
- goto reg_found;
- case 'q':
- /* eax, ebx, ecx or edx */
- for(reg = 0; reg < 4; reg++) {
- if (!is_reg_allocated(reg))
- goto reg_found;
- }
- goto try_next;
- case 'r':
- /* any general register */
- for(reg = 0; reg < 8; reg++) {
- if (!is_reg_allocated(reg))
- goto reg_found;
- }
- goto try_next;
- reg_found:
- /* now we can reload in the register */
- op->is_llong = 0;
- op->reg = reg;
- regs_allocated[reg] |= reg_mask;
- break;
- case 'i':
- if (!((op->vt->r & (VT_VALMASK | VT_LVAL)) == VT_CONST))
- goto try_next;
- break;
- case 'I':
- case 'N':
- case 'M':
- if (!((op->vt->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST))
- goto try_next;
- break;
- case 'm':
- case 'g':
- /* nothing special to do because the operand is already in
- memory, except if the pointer itself is stored in a
- memory variable (VT_LLOCAL case) */
- /* XXX: fix constant case */
- /* if it is a reference to a memory zone, it must lie
- in a register, so we reserve the register in the
- input registers and a load will be generated
- later */
- if (j < nb_outputs || c == 'm') {
- if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) {
- /* any general register */
- for(reg = 0; reg < 8; reg++) {
- if (!(regs_allocated[reg] & REG_IN_MASK))
- goto reg_found1;
- }
- goto try_next;
- reg_found1:
- /* now we can reload in the register */
- regs_allocated[reg] |= REG_IN_MASK;
- op->reg = reg;
- op->is_memory = 1;
- }
- }
- break;
- default:
- error("asm constraint %d ('%s') could not be satisfied",
- j, op->constraint);
- break;
- }
- /* if a reference is present for that operand, we assign it too */
- if (op->input_index >= 0) {
- operands[op->input_index].reg = op->reg;
- operands[op->input_index].is_llong = op->is_llong;
- }
- }
-
- /* compute out_reg. It is used to store outputs registers to memory
- locations references by pointers (VT_LLOCAL case) */
- *pout_reg = -1;
- for(i=0;i<nb_operands;i++) {
- op = &operands[i];
- if (op->reg >= 0 &&
- (op->vt->r & VT_VALMASK) == VT_LLOCAL &&
- !op->is_memory) {
- for(reg = 0; reg < 8; reg++) {
- if (!(regs_allocated[reg] & REG_OUT_MASK))
- goto reg_found2;
- }
- error("could not find free output register for reloading");
- reg_found2:
- *pout_reg = reg;
- break;
- }
- }
-
- /* print sorted constraints */
-#ifdef ASM_DEBUG
- for(i=0;i<nb_operands;i++) {
- j = sorted_op[i];
- op = &operands[j];
- printf("%%%d [%s]: \"%s\" r=0x%04x reg=%d\n",
- j,
- op->id ? get_tok_str(op->id, NULL) : "",
- op->constraint,
- op->vt->r,
- op->reg);
- }
- if (*pout_reg >= 0)
- printf("out_reg=%d\n", *pout_reg);
-#endif
-}
-
-static void subst_asm_operand(CString *add_str,
- SValue *sv, int modifier)
-{
- int r, reg, size, val;
- char buf[64];
-
- r = sv->r;
- if ((r & VT_VALMASK) == VT_CONST) {
- if (!(r & VT_LVAL) && modifier != 'c' && modifier != 'n')
- cstr_ccat(add_str, '$');
- if (r & VT_SYM) {
- cstr_cat(add_str, get_tok_str(sv->sym->v, NULL));
- if (sv->c.i != 0) {
- cstr_ccat(add_str, '+');
- } else {
- return;
- }
- }
- val = sv->c.i;
- if (modifier == 'n')
- val = -val;
- snprintf(buf, sizeof(buf), "%d", sv->c.i);
- cstr_cat(add_str, buf);
- } else if ((r & VT_VALMASK) == VT_LOCAL) {
- snprintf(buf, sizeof(buf), "%d(%%ebp)", sv->c.i);
- cstr_cat(add_str, buf);
- } else if (r & VT_LVAL) {
- reg = r & VT_VALMASK;
- if (reg >= VT_CONST)
- error("internal compiler error");
- snprintf(buf, sizeof(buf), "(%%%s)",
- get_tok_str(TOK_ASM_eax + reg, NULL));
- cstr_cat(add_str, buf);
- } else {
- /* register case */
- reg = r & VT_VALMASK;
- if (reg >= VT_CONST)
- error("internal compiler error");
-
- /* choose register operand size */
- if ((sv->type.t & VT_BTYPE) == VT_BYTE)
- size = 1;
- else if ((sv->type.t & VT_BTYPE) == VT_SHORT)
- size = 2;
- else if ((sv->type.t & VT_BTYPE) == VT_LLONG)
- size = 8;
- else
- size = 4;
- if (size == 1 && reg >= 4)
- size = 4;
-
- if (modifier == 'b') {
- if (reg >= 4)
- error("cannot use byte register");
- size = 1;
- } else if (modifier == 'h') {
- if (reg >= 4)
- error("cannot use byte register");
- size = -1;
- } else if (modifier == 'w') {
- size = 2;
- } else if (modifier == 'q') {
- size = 8;
- }
-
- switch(size) {
- case -1:
- reg = TOK_ASM_ah + reg;
- break;
- case 1:
- reg = TOK_ASM_al + reg;
- break;
- case 2:
- reg = TOK_ASM_ax + reg;
- break;
- case 4:
- reg = TOK_ASM_eax + reg;
- break;
- default:
- reg = TOK_ASM_rax + reg;
- break;
- }
- snprintf(buf, sizeof(buf), "%%%s", get_tok_str(reg, NULL));
- cstr_cat(add_str, buf);
- }
-}
-
-/* generate prolog and epilog code for asm statment */
-static void asm_gen_code(ASMOperand *operands, int nb_operands,
- int nb_outputs, int is_output,
- uint8_t *clobber_regs,
- int out_reg)
-{
- uint8_t regs_allocated[NB_ASM_REGS];
- ASMOperand *op;
- int i, reg;
- static uint8_t reg_saved[NB_SAVED_REGS] = { 3, 6, 7 };
-
- /* mark all used registers */
- memcpy(regs_allocated, clobber_regs, sizeof(regs_allocated));
- for(i = 0; i < nb_operands;i++) {
- op = &operands[i];
- if (op->reg >= 0)
- regs_allocated[op->reg] = 1;
- }
- if (!is_output) {
- /* generate reg save code */
- for(i = 0; i < NB_SAVED_REGS; i++) {
- reg = reg_saved[i];
- if (regs_allocated[reg])
- g(0x50 + reg);
- }
-
- /* generate load code */
- for(i = 0; i < nb_operands; i++) {
- op = &operands[i];
- if (op->reg >= 0) {
- if ((op->vt->r & VT_VALMASK) == VT_LLOCAL &&
- op->is_memory) {
- /* memory reference case (for both input and
- output cases) */
- SValue sv;
- sv = *op->vt;
- sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL;
- load(op->reg, &sv);
- } else if (i >= nb_outputs || op->is_rw) {
- /* load value in register */
- load(op->reg, op->vt);
- if (op->is_llong) {
- SValue sv;
- sv = *op->vt;
- sv.c.ul += 4;
- load(TREG_RDX, &sv);
- }
- }
- }
- }
- } else {
- /* generate save code */
- for(i = 0 ; i < nb_outputs; i++) {
- op = &operands[i];
- if (op->reg >= 0) {
- if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) {
- if (!op->is_memory) {
- SValue sv;
- sv = *op->vt;
- sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL;
- load(out_reg, &sv);
-
- sv.r = (sv.r & ~VT_VALMASK) | out_reg;
- store(op->reg, &sv);
- }
- } else {
- store(op->reg, op->vt);
- if (op->is_llong) {
- SValue sv;
- sv = *op->vt;
- sv.c.ul += 4;
- store(TREG_RDX, &sv);
- }
- }
- }
- }
- /* generate reg restore code */
- for(i = NB_SAVED_REGS - 1; i >= 0; i--) {
- reg = reg_saved[i];
- if (regs_allocated[reg])
- g(0x58 + reg);
- }
- }
-}
-
-static void asm_clobber(uint8_t *clobber_regs, const char *str)
-{
- int reg;
- TokenSym *ts;
-
- if (!strcmp(str, "memory") ||
- !strcmp(str, "cc"))
- return;
- ts = tok_alloc(str, strlen(str));
- reg = ts->tok;
- if (reg >= TOK_ASM_rax && reg <= TOK_ASM_rdi) {
- reg -= TOK_ASM_rax;
- } else if (reg >= TOK_ASM_eax && reg <= TOK_ASM_edi) {
- reg -= TOK_ASM_eax;
- } else if (reg >= TOK_ASM_ax && reg <= TOK_ASM_di) {
- reg -= TOK_ASM_ax;
- } else {
- error("invalid clobber register '%s'", str);
- }
- clobber_regs[reg] = 1;
-}
diff --git a/x86_64-gen.c b/x86_64-gen.c
index 052bf87..9f05889 100644
--- a/x86_64-gen.c
+++ b/x86_64-gen.c
@@ -123,6 +123,12 @@ void o(unsigned int c)
}
}
+void gen_le16(int v)
+{
+ g(v);
+ g(v >> 8);
+}
+
void gen_le32(int c)
{
g(c);
@@ -192,7 +198,13 @@ static int oad(int c, int s)
return s;
}
-#if 0
+static void gen_addr32(int r, Sym *sym, int c)
+{
+ if (r & VT_SYM)
+ greloc(cur_text_section, sym, ind, R_X86_64_32);
+ gen_le32(c);
+}
+
/* output constant with relocation if 'r & VT_SYM' is true */
static void gen_addr64(int r, Sym *sym, int64_t c)
{
@@ -200,7 +212,6 @@ static void gen_addr64(int r, Sym *sym, int64_t c)
greloc(cur_text_section, sym, ind, R_X86_64_64);
gen_le64(c);
}
-#endif
/* output constant with relocation if 'r & VT_SYM' is true */
static void gen_addrpc32(int r, Sym *sym, int c)
diff --git a/x86_64-tok.h b/x86_64-tok.h
deleted file mode 100644
index 406af84..0000000
--- a/x86_64-tok.h
+++ /dev/null
@@ -1,225 +0,0 @@
-
-/* WARNING: relative order of tokens is important. */
- DEF_ASM(al)
- DEF_ASM(cl)
- DEF_ASM(dl)
- DEF_ASM(bl)
- DEF_ASM(ah)
- DEF_ASM(ch)
- DEF_ASM(dh)
- DEF_ASM(bh)
- DEF_ASM(ax)
- DEF_ASM(cx)
- DEF_ASM(dx)
- DEF_ASM(bx)
- DEF_ASM(sp)
- DEF_ASM(bp)
- DEF_ASM(si)
- DEF_ASM(di)
- DEF_ASM(eax)
- DEF_ASM(ecx)
- DEF_ASM(edx)
- DEF_ASM(ebx)
- DEF_ASM(esp)
- DEF_ASM(ebp)
- DEF_ASM(esi)
- DEF_ASM(edi)
- DEF_ASM(rax)
- DEF_ASM(rcx)
- DEF_ASM(rdx)
- DEF_ASM(rbx)
- DEF_ASM(rsp)
- DEF_ASM(rbp)
- DEF_ASM(rsi)
- DEF_ASM(rdi)
- DEF_ASM(mm0)
- DEF_ASM(mm1)
- DEF_ASM(mm2)
- DEF_ASM(mm3)
- DEF_ASM(mm4)
- DEF_ASM(mm5)
- DEF_ASM(mm6)
- DEF_ASM(mm7)
- DEF_ASM(xmm0)
- DEF_ASM(xmm1)
- DEF_ASM(xmm2)
- DEF_ASM(xmm3)
- DEF_ASM(xmm4)
- DEF_ASM(xmm5)
- DEF_ASM(xmm6)
- DEF_ASM(xmm7)
- DEF_ASM(cr0)
- DEF_ASM(cr1)
- DEF_ASM(cr2)
- DEF_ASM(cr3)
- DEF_ASM(cr4)
- DEF_ASM(cr5)
- DEF_ASM(cr6)
- DEF_ASM(cr7)
- DEF_ASM(tr0)
- DEF_ASM(tr1)
- DEF_ASM(tr2)
- DEF_ASM(tr3)
- DEF_ASM(tr4)
- DEF_ASM(tr5)
- DEF_ASM(tr6)
- DEF_ASM(tr7)
- DEF_ASM(db0)
- DEF_ASM(db1)
- DEF_ASM(db2)
- DEF_ASM(db3)
- DEF_ASM(db4)
- DEF_ASM(db5)
- DEF_ASM(db6)
- DEF_ASM(db7)
- DEF_ASM(dr0)
- DEF_ASM(dr1)
- DEF_ASM(dr2)
- DEF_ASM(dr3)
- DEF_ASM(dr4)
- DEF_ASM(dr5)
- DEF_ASM(dr6)
- DEF_ASM(dr7)
- DEF_ASM(es)
- DEF_ASM(cs)
- DEF_ASM(ss)
- DEF_ASM(ds)
- DEF_ASM(fs)
- DEF_ASM(gs)
- DEF_ASM(st)
-
- DEF_BWLQ(mov)
-
- /* generic two operands */
- DEF_BWLQ(add)
- DEF_BWLQ(or)
- DEF_BWLQ(adc)
- DEF_BWLQ(sbb)
- DEF_BWLQ(and)
- DEF_BWLQ(sub)
- DEF_BWLQ(xor)
- DEF_BWLQ(cmp)
-
- /* unary ops */
- DEF_BWLQ(inc)
- DEF_BWLQ(dec)
- DEF_BWLQ(not)
- DEF_BWLQ(neg)
- DEF_BWLQ(mul)
- DEF_BWLQ(imul)
- DEF_BWLQ(div)
- DEF_BWLQ(idiv)
-
- DEF_BWLQ(xchg)
- DEF_BWLQ(test)
-
- /* shifts */
- DEF_BWLQ(rol)
- DEF_BWLQ(ror)
- DEF_BWLQ(rcl)
- DEF_BWLQ(rcr)
- DEF_BWLQ(shl)
- DEF_BWLQ(shr)
- DEF_BWLQ(sar)
-
- DEF_ASM(shldw)
- DEF_ASM(shldl)
- DEF_ASM(shld)
- DEF_ASM(shrdw)
- DEF_ASM(shrdl)
- DEF_ASM(shrd)
-
- DEF_ASM(pushw)
- DEF_ASM(pushl)
- DEF_ASM(pushq)
- DEF_ASM(push)
- DEF_ASM(popw)
- DEF_ASM(popl)
- DEF_ASM(popq)
- DEF_ASM(pop)
- DEF_BWL(in)
- DEF_BWL(out)
-
- DEF_WL(movzb)
-
- DEF_ASM(movzwl)
- DEF_ASM(movsbw)
- DEF_ASM(movsbl)
- DEF_ASM(movswl)
- DEF_ASM(movslq)
-
- DEF_WLQ(lea)
-
- DEF_ASM(les)
- DEF_ASM(lds)
- DEF_ASM(lss)
- DEF_ASM(lfs)
- DEF_ASM(lgs)
-
- DEF_ASM(call)
- DEF_ASM(jmp)
- DEF_ASM(lcall)
- DEF_ASM(ljmp)
-
- DEF_ASMTEST(j)
-
- DEF_ASMTEST(set)
- DEF_ASMTEST(cmov)
-
- DEF_WLQ(bsf)
- DEF_WLQ(bsr)
- DEF_WLQ(bt)
- DEF_WLQ(bts)
- DEF_WLQ(btr)
- DEF_WLQ(btc)
-
- DEF_WLQ(lsl)
-
- /* generic FP ops */
- DEF_FP(add)
- DEF_FP(mul)
-
- DEF_ASM(fcom)
- DEF_ASM(fcom_1) /* non existant op, just to have a regular table */
- DEF_FP1(com)
-
- DEF_FP(comp)
- DEF_FP(sub)
- DEF_FP(subr)
- DEF_FP(div)
- DEF_FP(divr)
-
- DEF_BWLQ(xadd)
- DEF_BWLQ(cmpxchg)
-
- /* string ops */
- DEF_BWLQ(cmps)
- DEF_BWLQ(scmp)
- DEF_BWL(ins)
- DEF_BWL(outs)
- DEF_BWLQ(lods)
- DEF_BWLQ(slod)
- DEF_BWLQ(movs)
- DEF_BWLQ(smov)
- DEF_BWLQ(scas)
- DEF_BWLQ(ssca)
- DEF_BWLQ(stos)
- DEF_BWLQ(ssto)
-
- /* generic asm ops */
-
-#define ALT(x)
-#define DEF_ASM_OP0(name, opcode) DEF_ASM(name)
-#define DEF_ASM_OP0L(name, opcode, group, instr_type)
-#define DEF_ASM_OP1(name, opcode, group, instr_type, op0)
-#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1)
-#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2)
-#include "x86_64-asm.h"
-
-#define ALT(x)
-#define DEF_ASM_OP0(name, opcode)
-#define DEF_ASM_OP0L(name, opcode, group, instr_type) DEF_ASM(name)
-#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) DEF_ASM(name)
-#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) DEF_ASM(name)
-#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) DEF_ASM(name)
-#include "x86_64-asm.h"