Changeset 331 for EcnlProtoTool/trunk/tcc-0.9.27/i386-asm.c
- Timestamp:
- Jan 21, 2018, 12:10:09 AM (6 years ago)
- Location:
- EcnlProtoTool/trunk/tcc-0.9.27
- Files:
-
- 1 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
EcnlProtoTool/trunk/tcc-0.9.27/i386-asm.c
r321 r331 22 22 #include "tcc.h" 23 23 24 // #define NB_ASM_REGS 825 24 #define MAX_OPERANDS 3 26 #define NB_SAVED_REGS 327 25 28 26 #define TOK_ASM_first TOK_ASM_clc 29 27 #define TOK_ASM_last TOK_ASM_emms 30 31 #define OPC_JMP 0x01 /* jmp operand */ 32 #define OPC_B 0x0 2/* only used with OPC_WL */33 #define OPC_WL 0x0 4/* accepts w, l or no suffix */28 #define TOK_ASM_alllast TOK_ASM_subps 29 30 #define OPC_B 0x01 /* only used with OPC_WL */ 31 #define OPC_WL 0x02 /* accepts w, l or no suffix */ 34 32 #define OPC_BWL (OPC_B | OPC_WL) /* accepts b, w, l or no suffix */ 35 #define OPC_REG 0x08 /* register is added to opcode */ 36 #define OPC_MODRM 0x10 /* modrm encoding */ 37 #define OPC_FWAIT 0x20 /* add fwait opcode */ 38 #define OPC_TEST 0x40 /* test opcodes */ 39 #define OPC_SHIFT 0x80 /* shift opcodes */ 40 #define OPC_D16 0x0100 /* generate data16 prefix */ 41 #define OPC_ARITH 0x0200 /* arithmetic opcodes */ 42 #define OPC_SHORTJMP 0x0400 /* short jmp operand */ 43 #define OPC_FARITH 0x0800 /* FPU arithmetic opcodes */ 33 #define OPC_REG 0x04 /* register is added to opcode */ 34 #define OPC_MODRM 0x08 /* modrm encoding */ 35 36 #define OPCT_MASK 0x70 37 #define OPC_FWAIT 0x10 /* add fwait opcode */ 38 #define OPC_SHIFT 0x20 /* shift opcodes */ 39 #define OPC_ARITH 0x30 /* arithmetic opcodes */ 40 #define OPC_FARITH 0x40 /* FPU arithmetic opcodes */ 41 #define OPC_TEST 0x50 /* test opcodes */ 42 #define OPCT_IS(v,i) (((v) & OPCT_MASK) == (i)) 43 44 #define OPC_0F 0x100 /* Is secondary map (0x0f prefix) */ 45 #define OPC_48 0x200 /* Always has REX prefix */ 44 46 #ifdef TCC_TARGET_X86_64 45 47 # define OPC_WLQ 0x1000 /* accepts w, l, q or no suffix */ 46 48 # define OPC_BWLQ (OPC_B | OPC_WLQ) /* accepts b, w, l, q or no suffix */ 47 49 # define OPC_WLX OPC_WLQ 50 # define OPC_BWLX OPC_BWLQ 48 51 #else 49 52 # define OPC_WLX OPC_WL 53 # define OPC_BWLX OPC_BWL 50 54 #endif 51 55 … … 68 72 OPT_SEG, 69 73 OPT_ST, 74 #ifdef TCC_TARGET_X86_64 75 OPT_REG8_LOW, /* %spl,%bpl,%sil,%dil, encoded like ah,ch,dh,bh, but 76 with REX prefix, not used in insn templates */ 77 #endif 70 78 OPT_IM8, 71 79 OPT_IM8S, … … 83 91 /* composite types */ 84 92 OPT_COMPOSITE_FIRST, 85 OPT_IM, /* IM8 | IM16 | IM32 | IM64*/93 OPT_IM, /* IM8 | IM16 | IM32 */ 86 94 OPT_REG, /* REG8 | REG16 | REG32 | REG64 */ 87 95 OPT_REGW, /* REG16 | REG32 | REG64 */ 88 OPT_IMW, /* IM16 | IM32 | IM64*/89 #ifdef TCC_TARGET_X86_64 90 OPT_ IMNO64, /* IM16 | IM32*/91 #endif 96 OPT_IMW, /* IM16 | IM32 */ 97 OPT_MMXSSE, /* MMX | SSE */ 98 OPT_DISP, /* Like OPT_ADDR, but emitted as displacement (for jumps) */ 99 OPT_DISP8, /* Like OPT_ADDR, but only 8bit (short jumps) */ 92 100 /* can be ored with any OPT_xxx */ 93 101 OPT_EA = 0x80 … … 115 123 #define OP_INDIR (1 << OPT_INDIR) 116 124 #ifdef TCC_TARGET_X86_64 117 # define OP_REG64 (1 << OPT_REG64) 118 # define OP_IM64 (1 << OPT_IM64) 125 # define OP_REG64 (1 << OPT_REG64) 126 # define OP_REG8_LOW (1 << OPT_REG8_LOW) 127 # define OP_IM64 (1 << OPT_IM64) 128 # define OP_EA32 (OP_EA << 1) 119 129 #else 120 130 # define OP_REG64 0 131 # define OP_REG8_LOW 0 121 132 # define OP_IM64 0 133 # define OP_EA32 0 122 134 #endif 123 135 … … 126 138 127 139 #ifdef TCC_TARGET_X86_64 128 # define OP_IM OP_IM64129 140 # define TREG_XAX TREG_RAX 130 141 # define TREG_XCX TREG_RCX 131 142 # define TREG_XDX TREG_RDX 132 143 #else 133 # define OP_IM OP_IM32134 144 # define TREG_XAX TREG_EAX 135 145 # define TREG_XCX TREG_ECX … … 211 221 static const ASMInstr asm_instrs[] = { 212 222 #define ALT(x) x 223 /* This removes a 0x0f in the second byte */ 224 #define O(o) ((uint64_t) ((((o) & 0xff00) == 0x0f00) ? ((((o) >> 8) & ~0xff) | ((o) & 0xff)) : (o))) 225 /* This constructs instr_type from opcode, type and group. */ 226 #define T(o,i,g) ((i) | ((g) << OPC_GROUP_SHIFT) | ((((o) & 0xff00) == 0x0f00) ? OPC_0F : 0)) 213 227 #define DEF_ASM_OP0(name, opcode) 214 #define DEF_ASM_OP0L(name, opcode, group, instr_type) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 0},215 #define DEF_ASM_OP1(name, opcode, group, instr_type, op0) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 1, { op0 }},216 #define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 2, { op0, op1 }},217 #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 }},228 #define DEF_ASM_OP0L(name, opcode, group, instr_type) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 0, { 0 } }, 229 #define DEF_ASM_OP1(name, opcode, group, instr_type, op0) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 1, { op0 }}, 230 #define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 2, { op0, op1 }}, 231 #define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 3, { op0, op1, op2 }}, 218 232 #ifdef TCC_TARGET_X86_64 219 233 # include "x86_64-asm.h" … … 242 256 { 243 257 int shift, v; 244 #ifdef I386_ASM_16245 if (s1->seg_size == 16)246 tcc_error("invalid effective address");247 #endif248 258 v = asm_int_expr(s1); 249 259 switch(v) { … … 268 278 } 269 279 270 static int asm_parse_reg(void) 280 #ifdef TCC_TARGET_X86_64 281 static int asm_parse_numeric_reg(int t, unsigned int *type) 282 { 283 int reg = -1; 284 if (t >= TOK_IDENT && t < tok_ident) { 285 const char *s = table_ident[t - TOK_IDENT]->str; 286 char c; 287 *type = OP_REG64; 288 if (*s == 'c') { 289 s++; 290 *type = OP_CR; 291 } 292 if (*s++ != 'r') 293 return -1; 294 /* Don't allow leading '0'. */ 295 if ((c = *s++) >= '1' && c <= '9') 296 reg = c - '0'; 297 else 298 return -1; 299 if ((c = *s) >= '0' && c <= '5') 300 s++, reg = reg * 10 + c - '0'; 301 if (reg > 15) 302 return -1; 303 if ((c = *s) == 0) 304 ; 305 else if (*type != OP_REG64) 306 return -1; 307 else if (c == 'b' && !s[1]) 308 *type = OP_REG8; 309 else if (c == 'w' && !s[1]) 310 *type = OP_REG16; 311 else if (c == 'd' && !s[1]) 312 *type = OP_REG32; 313 else 314 return -1; 315 } 316 return reg; 317 } 318 #endif 319 320 static int asm_parse_reg(unsigned int *type) 271 321 { 272 322 int reg = 0; 323 *type = 0; 273 324 if (tok != '%') 274 325 goto error_32; … … 276 327 if (tok >= TOK_ASM_eax && tok <= TOK_ASM_edi) { 277 328 reg = tok - TOK_ASM_eax; 329 *type = OP_REG32; 278 330 #ifdef TCC_TARGET_X86_64 279 331 } else if (tok >= TOK_ASM_rax && tok <= TOK_ASM_rdi) { 280 332 reg = tok - TOK_ASM_rax; 281 #endif 282 #ifdef I386_ASM_16 283 } else if (tok >= TOK_ASM_ax && tok <= TOK_ASM_di) { 284 reg = tok - TOK_ASM_ax; 333 *type = OP_REG64; 334 } else if (tok == TOK_ASM_rip) { 335 reg = -2; /* Probably should use different escape code. */ 336 *type = OP_REG64; 337 } else if ((reg = asm_parse_numeric_reg(tok, type)) >= 0 338 && (*type == OP_REG32 || *type == OP_REG64)) { 339 ; 285 340 #endif 286 341 } else { … … 330 385 if (tok != TOK_PPNUM) 331 386 goto reg_error; 332 p = tokc. cstr->data;387 p = tokc.str.data; 333 388 reg = p[0] - '0'; 334 389 if ((unsigned)reg >= 8 || p[1] != '\0') … … 341 396 op->type |= OP_ST0; 342 397 goto no_skip; 398 #ifdef TCC_TARGET_X86_64 399 } else if (tok >= TOK_ASM_spl && tok <= TOK_ASM_dil) { 400 op->type = OP_REG8 | OP_REG8_LOW; 401 op->reg = 4 + tok - TOK_ASM_spl; 402 } else if ((op->reg = asm_parse_numeric_reg(tok, &op->type)) >= 0) { 403 ; 404 #endif 343 405 } else { 344 406 reg_error: 345 tcc_error("unknown register ");407 tcc_error("unknown register %%%s", get_tok_str(tok, &tokc)); 346 408 } 347 409 next(); … … 351 413 next(); 352 414 asm_expr(s1, &e); 353 op->type = OP_IM; 354 op->e.v = e.v; 355 op->e.sym = e.sym; 415 op->type = OP_IM32; 416 op->e = e; 356 417 if (!op->e.sym) { 357 418 if (op->e.v == (uint8_t)op->e.v) … … 362 423 op->type |= OP_IM16; 363 424 #ifdef TCC_TARGET_X86_64 364 if (op->e.v == (uint32_t)op->e.v)365 op->type |= OP_IM32;425 if (op->e.v != (int32_t)op->e.v && op->e.v != (uint32_t)op->e.v) 426 op->type = OP_IM64; 366 427 #endif 367 428 } … … 374 435 if (tok != '(') { 375 436 asm_expr(s1, &e); 376 op->e.v = e.v; 377 op->e.sym = e.sym; 437 op->e = e; 378 438 } else { 379 439 next(); … … 391 451 op->e.sym = e.sym; 392 452 } 453 op->e.pcrel = 0; 393 454 } 394 455 if (tok == '(') { 456 unsigned int type = 0; 395 457 next(); 396 458 if (tok != ',') { 397 op->reg = asm_parse_reg( );459 op->reg = asm_parse_reg(&type); 398 460 } 399 461 if (tok == ',') { 400 462 next(); 401 463 if (tok != ',') { 402 op->reg2 = asm_parse_reg( );464 op->reg2 = asm_parse_reg(&type); 403 465 } 404 466 if (tok == ',') { … … 407 469 } 408 470 } 471 if (type & OP_REG32) 472 op->type |= OP_EA32; 409 473 skip(')'); 410 474 } … … 418 482 ST_FUNC void gen_expr32(ExprValue *pe) 419 483 { 420 gen_addr32(pe->sym ? VT_SYM : 0, pe->sym, pe->v); 484 if (pe->pcrel) 485 /* If PC-relative, always set VT_SYM, even without symbol, 486 so as to force a relocation to be emitted. */ 487 gen_addrpc32(VT_SYM, pe->sym, pe->v); 488 else 489 gen_addr32(pe->sym ? VT_SYM : 0, pe->sym, pe->v); 421 490 } 422 491 423 492 #ifdef TCC_TARGET_X86_64 424 staticvoid gen_expr64(ExprValue *pe)493 ST_FUNC void gen_expr64(ExprValue *pe) 425 494 { 426 495 gen_addr64(pe->sym ? VT_SYM : 0, pe->sym, pe->v); … … 432 501 { 433 502 Sym *sym = pe->sym; 434 if (sym && sym->r == cur_text_section->sh_num) { 503 ElfSym *esym = elfsym(sym); 504 if (esym && esym->st_shndx == cur_text_section->sh_num) { 435 505 /* same section: we can output an absolute value. Note 436 506 that the TCC compiler behaves differently here because 437 507 it always outputs a relocation to ease (future) code 438 508 elimination in the linker */ 439 gen_le32(pe->v + sym->jnext- ind - 4);509 gen_le32(pe->v + esym->st_value - ind - 4); 440 510 } else { 441 511 if (sym && sym->type.t == VT_VOID) { … … 447 517 } 448 518 449 #ifdef I386_ASM_16450 static void gen_expr16(ExprValue *pe)451 {452 if (pe->sym)453 greloc(cur_text_section, pe->sym, ind, R_386_16);454 gen_le16(pe->v);455 }456 static void gen_disp16(ExprValue *pe)457 {458 Sym *sym;459 sym = pe->sym;460 if (sym) {461 if (sym->r == cur_text_section->sh_num) {462 /* same section: we can output an absolute value. Note463 that the TCC compiler behaves differently here because464 it always outputs a relocation to ease (future) code465 elimination in the linker */466 gen_le16(pe->v + sym->jnext - ind - 2);467 } else {468 greloc(cur_text_section, sym, ind, R_386_PC16);469 gen_le16(pe->v - 2);470 }471 } else {472 /* put an empty PC32 relocation */473 put_elf_reloc(symtab_section, cur_text_section,474 ind, R_386_PC16, 0);475 gen_le16(pe->v - 2);476 }477 }478 #endif479 480 519 /* generate the modrm operand */ 481 static inline voidasm_modrm(int reg, Operand *op)520 static inline int asm_modrm(int reg, Operand *op) 482 521 { 483 522 int mod, reg1, reg2, sib_reg1; … … 487 526 } else if (op->reg == -1 && op->reg2 == -1) { 488 527 /* displacement only */ 489 #ifdef I386_ASM_16 490 if (tcc_state->seg_size == 16) { 491 g(0x06 + (reg << 3)); 492 gen_expr16(&op->e); 493 } else if (tcc_state->seg_size == 32) 494 #endif 495 { 496 g(0x05 + (reg << 3)); 497 gen_expr32(&op->e); 498 } 528 #ifdef TCC_TARGET_X86_64 529 g(0x04 + (reg << 3)); 530 g(0x25); 531 #else 532 g(0x05 + (reg << 3)); 533 #endif 534 gen_expr32(&op->e); 535 #ifdef TCC_TARGET_X86_64 536 } else if (op->reg == -2) { 537 ExprValue *pe = &op->e; 538 g(0x05 + (reg << 3)); 539 gen_addrpc32(pe->sym ? VT_SYM : 0, pe->sym, pe->v); 540 return ind; 541 #endif 499 542 } else { 500 543 sib_reg1 = op->reg; … … 514 557 if (op->reg2 != -1) 515 558 reg1 = 4; 516 #ifdef I386_ASM_16517 if (tcc_state->seg_size == 32) {518 #endif519 559 g(mod + (reg << 3) + reg1); 520 560 if (reg1 == 4) { … … 525 565 g((op->shift << 6) + (reg2 << 3) + sib_reg1); 526 566 } 527 #ifdef I386_ASM_16528 } else if (tcc_state->seg_size == 16) {529 /* edi = 7, esi = 6 --> di = 5, si = 4 */530 if ((reg1 == 6) || (reg1 == 7)) {531 reg1 -= 2;532 /* ebx = 3 --> bx = 7 */533 } else if (reg1 == 3) {534 reg1 = 7;535 /* o32 = 5 --> o16 = 6 */536 } else if (reg1 == 5) {537 reg1 = 6;538 /* sib not valid in 16-bit mode */539 } else if (reg1 == 4) {540 reg2 = op->reg2;541 /* bp + si + offset */542 if ((sib_reg1 == 5) && (reg2 == 6)) {543 reg1 = 2;544 /* bp + di + offset */545 } else if ((sib_reg1 == 5) && (reg2 == 7)) {546 reg1 = 3;547 /* bx + si + offset */548 } else if ((sib_reg1 == 3) && (reg2 == 6)) {549 reg1 = 0;550 /* bx + di + offset */551 } else if ((sib_reg1 == 3) && (reg2 == 7)) {552 reg1 = 1;553 } else {554 tcc_error("invalid effective address");555 }556 if (op->e.v == 0)557 mod = 0;558 } else {559 tcc_error("invalid register");560 }561 g(mod + (reg << 3) + reg1);562 }563 #endif564 567 /* add offset */ 565 568 if (mod == 0x40) { 566 569 g(op->e.v); 567 570 } else if (mod == 0x80 || op->reg == -1) { 568 #ifdef I386_ASM_16 569 if (tcc_state->seg_size == 16) 570 gen_expr16(&op->e); 571 else if (tcc_state->seg_size == 32) 572 #endif 573 gen_expr32(&op->e); 574 } 571 gen_expr32(&op->e); 572 } 573 } 574 return 0; 575 } 576 577 #ifdef TCC_TARGET_X86_64 578 #define REX_W 0x48 579 #define REX_R 0x44 580 #define REX_X 0x42 581 #define REX_B 0x41 582 583 static void asm_rex(int width64, Operand *ops, int nb_ops, int *op_type, 584 int regi, int rmi) 585 { 586 unsigned char rex = width64 ? 0x48 : 0; 587 int saw_high_8bit = 0; 588 int i; 589 if (rmi == -1) { 590 /* No mod/rm byte, but we might have a register op nevertheless 591 (we will add it to the opcode later). */ 592 for(i = 0; i < nb_ops; i++) { 593 if (op_type[i] & (OP_REG | OP_ST)) { 594 if (ops[i].reg >= 8) { 595 rex |= REX_B; 596 ops[i].reg -= 8; 597 } else if (ops[i].type & OP_REG8_LOW) 598 rex |= 0x40; 599 else if (ops[i].type & OP_REG8 && ops[i].reg >= 4) 600 /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */ 601 saw_high_8bit = ops[i].reg; 602 break; 603 } 604 } 605 } else { 606 if (regi != -1) { 607 if (ops[regi].reg >= 8) { 608 rex |= REX_R; 609 ops[regi].reg -= 8; 610 } else if (ops[regi].type & OP_REG8_LOW) 611 rex |= 0x40; 612 else if (ops[regi].type & OP_REG8 && ops[regi].reg >= 4) 613 /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */ 614 saw_high_8bit = ops[regi].reg; 615 } 616 if (ops[rmi].type & (OP_REG | OP_MMX | OP_SSE | OP_CR | OP_EA)) { 617 if (ops[rmi].reg >= 8) { 618 rex |= REX_B; 619 ops[rmi].reg -= 8; 620 } else if (ops[rmi].type & OP_REG8_LOW) 621 rex |= 0x40; 622 else if (ops[rmi].type & OP_REG8 && ops[rmi].reg >= 4) 623 /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */ 624 saw_high_8bit = ops[rmi].reg; 625 } 626 if (ops[rmi].type & OP_EA && ops[rmi].reg2 >= 8) { 627 rex |= REX_X; 628 ops[rmi].reg2 -= 8; 629 } 630 } 631 if (rex) { 632 if (saw_high_8bit) 633 tcc_error("can't encode register %%%ch when REX prefix is required", 634 "acdb"[saw_high_8bit-4]); 635 g(rex); 636 } 637 } 638 #endif 639 640 static void maybe_print_stats (void) 641 { 642 static int already = 1; 643 if (!already) 644 /* print stats about opcodes */ 645 { 646 const struct ASMInstr *pa; 647 int freq[4]; 648 int op_vals[500]; 649 int nb_op_vals, i, j; 650 651 already = 1; 652 nb_op_vals = 0; 653 memset(freq, 0, sizeof(freq)); 654 for(pa = asm_instrs; pa->sym != 0; pa++) { 655 freq[pa->nb_ops]++; 656 //for(i=0;i<pa->nb_ops;i++) { 657 for(j=0;j<nb_op_vals;j++) { 658 //if (pa->op_type[i] == op_vals[j]) 659 if (pa->instr_type == op_vals[j]) 660 goto found; 661 } 662 //op_vals[nb_op_vals++] = pa->op_type[i]; 663 op_vals[nb_op_vals++] = pa->instr_type; 664 found: ; 665 //} 666 } 667 for(i=0;i<nb_op_vals;i++) { 668 int v = op_vals[i]; 669 //if ((v & (v - 1)) != 0) 670 printf("%3d: %08x\n", i, v); 671 } 672 printf("size=%d nb=%d f0=%d f1=%d f2=%d f3=%d\n", 673 (int)sizeof(asm_instrs), 674 (int)sizeof(asm_instrs) / (int)sizeof(ASMInstr), 675 freq[0], freq[1], freq[2], freq[3]); 575 676 } 576 677 } … … 579 680 { 580 681 const ASMInstr *pa; 581 int i, modrm_index, reg, v, op1, is_short_jmp, seg_prefix;682 int i, modrm_index, modreg_index, reg, v, op1, seg_prefix, pc; 582 683 int nb_ops, s; 583 684 Operand ops[MAX_OPERANDS], *pop; 584 685 int op_type[3]; /* decoded op type */ 585 #ifdef I386_ASM_16 586 static int a32 = 0, o32 = 0, addr32 = 0, data32 = 0; 587 #endif 588 686 int alltypes; /* OR of all operand types */ 687 int autosize; 688 int p66; 689 #ifdef TCC_TARGET_X86_64 690 int rex64; 691 #endif 692 693 maybe_print_stats(); 589 694 /* force synthetic ';' after prefix instruction, so we can handle */ 590 695 /* one-line things like "rep stosb" instead of only "rep\nstosb" */ … … 596 701 nb_ops = 0; 597 702 seg_prefix = 0; 703 alltypes = 0; 598 704 for(;;) { 599 705 if (tok == ';' || tok == TOK_LINEFEED) … … 609 715 next(); 610 716 parse_operand(s1, pop); 611 #ifndef I386_ASM_16612 717 if (!(pop->type & OP_EA)) { 613 718 tcc_error("segment prefix must be followed by memory reference"); 614 719 } 615 #endif616 720 } 617 721 pop++; … … 622 726 } 623 727 624 is_short_jmp = 0;625 728 s = 0; /* avoid warning */ 626 729 730 again: 627 731 /* optimize matching by using a lookup table (no hashing is needed 628 732 !) */ 629 733 for(pa = asm_instrs; pa->sym != 0; pa++) { 734 int it = pa->instr_type & OPCT_MASK; 630 735 s = 0; 631 if ( pa->instr_type &OPC_FARITH) {736 if (it == OPC_FARITH) { 632 737 v = opcode - pa->sym; 633 738 if (!((unsigned)v < 8 * 6 && (v % 6) == 0)) 634 739 continue; 635 } else if ( pa->instr_type &OPC_ARITH) {740 } else if (it == OPC_ARITH) { 636 741 if (!(opcode >= pa->sym && opcode < pa->sym + 8*NBWLX)) 637 742 continue; 638 743 s = (opcode - pa->sym) % NBWLX; 639 } else if (pa->instr_type & OPC_SHIFT) { 744 if ((pa->instr_type & OPC_BWLX) == OPC_WLX) 745 { 746 /* We need to reject the xxxb opcodes that we accepted above. 747 Note that pa->sym for WLX opcodes is the 'w' token, 748 to get the 'b' token subtract one. */ 749 if (((opcode - pa->sym + 1) % NBWLX) == 0) 750 continue; 751 s++; 752 } 753 } else if (it == OPC_SHIFT) { 640 754 if (!(opcode >= pa->sym && opcode < pa->sym + 7*NBWLX)) 641 755 continue; 642 756 s = (opcode - pa->sym) % NBWLX; 643 } else if ( pa->instr_type &OPC_TEST) {757 } else if (it == OPC_TEST) { 644 758 if (!(opcode >= pa->sym && opcode < pa->sym + NB_TEST_OPCODES)) 645 759 continue; 760 /* cmovxx is a test opcode but accepts multiple sizes. 761 The suffixes aren't encoded in the table, instead we 762 simply force size autodetection always and deal with suffixed 763 variants below when we don't find e.g. "cmovzl". */ 764 if (pa->instr_type & OPC_WLX) 765 s = NBWLX - 1; 646 766 } else if (pa->instr_type & OPC_B) { 767 #ifdef TCC_TARGET_X86_64 768 /* Some instructions don't have the full size but only 769 bwl form. insb e.g. */ 770 if ((pa->instr_type & OPC_WLQ) != OPC_WLQ 771 && !(opcode >= pa->sym && opcode < pa->sym + NBWLX-1)) 772 continue; 773 #endif 647 774 if (!(opcode >= pa->sym && opcode < pa->sym + NBWLX)) 648 775 continue; … … 658 785 if (pa->nb_ops != nb_ops) 659 786 continue; 787 #ifdef TCC_TARGET_X86_64 788 /* Special case for moves. Selecting the IM64->REG64 form 789 should only be done if we really have an >32bit imm64, and that 790 is hardcoded. Ignore it here. */ 791 if (pa->opcode == 0xb0 && ops[0].type != OP_IM64 792 && (ops[1].type & OP_REG) == OP_REG64 793 && !(pa->instr_type & OPC_0F)) 794 continue; 795 #endif 660 796 /* now decode and check each operand */ 797 alltypes = 0; 661 798 for(i = 0; i < nb_ops; i++) { 662 799 int op1, op2; … … 665 802 switch(op2) { 666 803 case OPT_IM: 667 v = OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64;804 v = OP_IM8 | OP_IM16 | OP_IM32; 668 805 break; 669 806 case OPT_REG: … … 674 811 break; 675 812 case OPT_IMW: 676 v = OP_IM16 | OP_IM32 | OP_IM64;677 break;678 #ifdef TCC_TARGET_X86_64679 case OPT_IMNO64:680 813 v = OP_IM16 | OP_IM32; 681 814 break; 682 #endif 815 case OPT_MMXSSE: 816 v = OP_MMX | OP_SSE; 817 break; 818 case OPT_DISP: 819 case OPT_DISP8: 820 v = OP_ADDR; 821 break; 683 822 default: 684 823 v = 1 << op2; … … 687 826 if (op1 & OPT_EA) 688 827 v |= OP_EA; 689 828 op_type[i] = v; 690 829 if ((ops[i].type & v) == 0) 691 830 goto next; 831 alltypes |= ops[i].type; 692 832 } 693 833 /* all is matching ! */ … … 699 839 int b; 700 840 b = op0_codes[opcode - TOK_ASM_first]; 701 #ifdef I386_ASM_16702 if (opcode == TOK_ASM_o32) {703 if (s1->seg_size == 32)704 tcc_error("incorrect prefix");705 else706 o32 = data32 = 1;707 } else if (opcode == TOK_ASM_a32) {708 if (s1->seg_size == 32)709 tcc_error("incorrect prefix");710 else711 a32 = addr32 = 1;712 }713 #endif714 841 if (b & 0xff00) 715 842 g(b >> 8); 716 843 g(b); 717 844 return; 845 } else if (opcode <= TOK_ASM_alllast) { 846 tcc_error("bad operand with opcode '%s'", 847 get_tok_str(opcode, NULL)); 718 848 } else { 719 tcc_error("unknown opcode '%s'", 720 get_tok_str(opcode, NULL)); 849 /* Special case for cmovcc, we accept size suffixes but ignore 850 them, but we don't want them to blow up our tables. */ 851 TokenSym *ts = table_ident[opcode - TOK_IDENT]; 852 if (ts->len >= 6 853 && strchr("wlq", ts->str[ts->len-1]) 854 && !memcmp(ts->str, "cmov", 4)) { 855 opcode = tok_alloc(ts->str, ts->len-1)->tok; 856 goto again; 857 } 858 tcc_error("unknown opcode '%s'", ts->str); 721 859 } 722 860 } 723 861 /* if the size is unknown, then evaluate it (OPC_B or OPC_WL case) */ 724 if (s == NBWLX-1) { 725 for(i = 0; s == NBWLX-1 && i < nb_ops; i++) { 862 autosize = NBWLX-1; 863 #ifdef TCC_TARGET_X86_64 864 /* XXX the autosize should rather be zero, to not have to adjust this 865 all the time. */ 866 if ((pa->instr_type & OPC_BWLQ) == OPC_B) 867 autosize = NBWLX-2; 868 #endif 869 if (s == autosize) { 870 /* Check for register operands providing hints about the size. 871 Start from the end, i.e. destination operands. This matters 872 only for opcodes accepting different sized registers, lar and lsl 873 are such opcodes. */ 874 for(i = nb_ops - 1; s == autosize && i >= 0; i--) { 726 875 if ((ops[i].type & OP_REG) && !(op_type[i] & (OP_CL | OP_DX))) 727 876 s = reg_to_size[ops[i].type & OP_REG]; 728 877 } 729 if (s == NBWLX-1) {878 if (s == autosize) { 730 879 if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) && 731 (ops[0].type & (OP_SEG | OP_IM8S | OP_IM32 | OP_IM64)))880 (ops[0].type & (OP_SEG | OP_IM8S | OP_IM32))) 732 881 s = 2; 882 else if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) && 883 (ops[0].type & OP_EA)) 884 s = NBWLX - 2; 733 885 else 734 886 tcc_error("cannot infer opcode suffix"); … … 736 888 } 737 889 738 #ifdef I386_ASM_16 890 #ifdef TCC_TARGET_X86_64 891 /* Generate addr32 prefix if needed */ 739 892 for(i = 0; i < nb_ops; i++) { 740 if (ops[i].type & OP_REG32) { 741 if (s1->seg_size == 16) 742 o32 = 1; 743 } else if (!(ops[i].type & OP_REG32)) { 744 if (s1->seg_size == 32) 745 o32 = 1; 746 } 747 } 748 749 750 if (s == 1 || (pa->instr_type & OPC_D16)) { 751 if (s1->seg_size == 32) 752 o32 = 1; 753 } else if (s == 2) { 754 if (s1->seg_size == 16) { 755 if (!(pa->instr_type & OPC_D16)) 756 o32 = 1; 757 } 758 } 759 760 /* generate a16/a32 prefix if needed */ 761 if ((a32 == 1) && (addr32 == 0)) 762 g(0x67); 763 /* generate o16/o32 prefix if needed */ 764 if ((o32 == 1) && (data32 == 0)) 893 if (ops[i].type & OP_EA32) { 894 g(0x67); 895 break; 896 } 897 } 898 #endif 899 /* generate data16 prefix if needed */ 900 p66 = 0; 901 if (s == 1) 902 p66 = 1; 903 else { 904 /* accepting mmx+sse in all operands --> needs 0x66 to 905 switch to sse mode. Accepting only sse in an operand --> is 906 already SSE insn and needs 0x66/f2/f3 handling. */ 907 for (i = 0; i < nb_ops; i++) 908 if ((op_type[i] & (OP_MMX | OP_SSE)) == (OP_MMX | OP_SSE) 909 && ops[i].type & OP_SSE) 910 p66 = 1; 911 } 912 if (p66) 765 913 g(0x66); 766 767 addr32 = data32 = 0; 768 #else 769 /* generate data16 prefix if needed */ 770 if (s == 1 || (pa->instr_type & OPC_D16)) 771 g(0x66); 772 #ifdef TCC_TARGET_X86_64 773 else if (s == 3) { 914 #ifdef TCC_TARGET_X86_64 915 rex64 = 0; 916 if (pa->instr_type & OPC_48) 917 rex64 = 1; 918 else if (s == 3 || (alltypes & OP_REG64)) { 774 919 /* generate REX prefix */ 775 if ((opcode != TOK_ASM_push && opcode != TOK_ASM_pop) 776 || !(ops[0].type & OP_REG64)) 777 g(0x48); 778 } 779 #endif 920 int default64 = 0; 921 for(i = 0; i < nb_ops; i++) { 922 if (op_type[i] == OP_REG64 && pa->opcode != 0xb8) { 923 /* If only 64bit regs are accepted in one operand 924 this is a default64 instruction without need for 925 REX prefixes, except for movabs(0xb8). */ 926 default64 = 1; 927 break; 928 } 929 } 930 /* XXX find better encoding for the default64 instructions. */ 931 if (((opcode != TOK_ASM_push && opcode != TOK_ASM_pop 932 && opcode != TOK_ASM_pushw && opcode != TOK_ASM_pushl 933 && opcode != TOK_ASM_pushq && opcode != TOK_ASM_popw 934 && opcode != TOK_ASM_popl && opcode != TOK_ASM_popq 935 && opcode != TOK_ASM_call && opcode != TOK_ASM_jmp)) 936 && !default64) 937 rex64 = 1; 938 } 780 939 #endif 781 940 782 941 /* now generates the operation */ 783 if ( pa->instr_type & OPC_FWAIT)942 if (OPCT_IS(pa->instr_type, OPC_FWAIT)) 784 943 g(0x9b); 785 944 if (seg_prefix) … … 787 946 788 947 v = pa->opcode; 948 if (pa->instr_type & OPC_0F) 949 v = ((v & ~0xff) << 8) | 0x0f00 | (v & 0xff); 789 950 if ((v == 0x69 || v == 0x6b) && nb_ops == 2) { 790 951 /* kludge for imul $im, %reg */ … … 806 967 /* arith case */ 807 968 v += ((opcode - TOK_ASM_addb) / NBWLX) << 3; 808 } else if ((pa->instr_type & (OPC _FARITH| OPC_MODRM)) == OPC_FARITH) {969 } else if ((pa->instr_type & (OPCT_MASK | OPC_MODRM)) == OPC_FARITH) { 809 970 /* fpu arith case */ 810 971 v += ((opcode - pa->sym) / 6) << 3; 811 972 } 973 974 /* search which operand will be used for modrm */ 975 modrm_index = -1; 976 modreg_index = -1; 977 if (pa->instr_type & OPC_MODRM) { 978 if (!nb_ops) { 979 /* A modrm opcode without operands is a special case (e.g. mfence). 980 It has a group and acts as if there's an register operand 0 981 (ax). */ 982 i = 0; 983 ops[i].type = OP_REG; 984 ops[i].reg = 0; 985 goto modrm_found; 986 } 987 /* first look for an ea operand */ 988 for(i = 0;i < nb_ops; i++) { 989 if (op_type[i] & OP_EA) 990 goto modrm_found; 991 } 992 /* then if not found, a register or indirection (shift instructions) */ 993 for(i = 0;i < nb_ops; i++) { 994 if (op_type[i] & (OP_REG | OP_MMX | OP_SSE | OP_INDIR)) 995 goto modrm_found; 996 } 997 #ifdef ASM_DEBUG 998 tcc_error("bad op table"); 999 #endif 1000 modrm_found: 1001 modrm_index = i; 1002 /* if a register is used in another operand then it is 1003 used instead of group */ 1004 for(i = 0;i < nb_ops; i++) { 1005 int t = op_type[i]; 1006 if (i != modrm_index && 1007 (t & (OP_REG | OP_MMX | OP_SSE | OP_CR | OP_TR | OP_DB | OP_SEG))) { 1008 modreg_index = i; 1009 break; 1010 } 1011 } 1012 } 1013 #ifdef TCC_TARGET_X86_64 1014 asm_rex (rex64, ops, nb_ops, op_type, modreg_index, modrm_index); 1015 #endif 1016 812 1017 if (pa->instr_type & OPC_REG) { 1018 /* mov $im, %reg case */ 1019 if (v == 0xb0 && s >= 1) 1020 v += 7; 813 1021 for(i = 0; i < nb_ops; i++) { 814 1022 if (op_type[i] & (OP_REG | OP_ST)) { … … 817 1025 } 818 1026 } 819 /* mov $im, %reg case */820 if (pa->opcode == 0xb0 && s >= 1)821 v += 7;822 1027 } 823 1028 if (pa->instr_type & OPC_B) 824 1029 v += s >= 1; 825 if (pa->instr_type & OPC_TEST) 826 v += test_bits[opcode - pa->sym]; 827 if (pa->instr_type & OPC_SHORTJMP) { 828 Sym *sym; 1030 if (nb_ops == 1 && pa->op_type[0] == OPT_DISP8) { 1031 ElfSym *esym; 829 1032 int jmp_disp; 830 1033 831 1034 /* see if we can really generate the jump with a byte offset */ 832 sym = ops[0].e.sym;833 if (! sym)1035 esym = elfsym(ops[0].e.sym); 1036 if (!esym || esym->st_shndx != cur_text_section->sh_num) 834 1037 goto no_short_jump; 835 if (sym->r != cur_text_section->sh_num) 836 goto no_short_jump; 837 jmp_disp = ops[0].e.v + sym->jnext - ind - 2; 1038 jmp_disp = ops[0].e.v + esym->st_value - ind - 2 - (v >= 0xff); 838 1039 if (jmp_disp == (int8_t)jmp_disp) { 839 1040 /* OK to generate jump */ 840 is_short_jmp = 1;1041 ops[0].e.sym = 0; 841 1042 ops[0].e.v = jmp_disp; 1043 op_type[0] = OP_IM8S; 842 1044 } else { 843 1045 no_short_jump: 844 if (pa->instr_type & OPC_JMP) { 845 /* long jump will be allowed. need to modify the 846 opcode slightly */ 847 if (v == 0xeb) 848 v = 0xe9; 849 else 850 v += 0x0f10; 851 } else { 852 tcc_error("invalid displacement"); 853 } 854 } 855 } 856 op1 = v >> 8; 1046 /* long jump will be allowed. need to modify the 1047 opcode slightly */ 1048 if (v == 0xeb) /* jmp */ 1049 v = 0xe9; 1050 else if (v == 0x70) /* jcc */ 1051 v += 0x0f10; 1052 else 1053 tcc_error("invalid displacement"); 1054 } 1055 } 1056 if (OPCT_IS(pa->instr_type, OPC_TEST)) 1057 v += test_bits[opcode - pa->sym]; 1058 op1 = v >> 16; 1059 if (op1) 1060 g(op1); 1061 op1 = (v >> 8) & 0xff; 857 1062 if (op1) 858 1063 g(op1); 859 1064 g(v); 860 1065 861 /* search which operand will used for modrm */ 862 modrm_index = 0; 863 if (pa->instr_type & OPC_SHIFT) { 1066 if (OPCT_IS(pa->instr_type, OPC_SHIFT)) { 864 1067 reg = (opcode - pa->sym) / NBWLX; 865 1068 if (reg == 6) 866 1069 reg = 7; 867 } else if ( pa->instr_type & OPC_ARITH) {1070 } else if (OPCT_IS(pa->instr_type, OPC_ARITH)) { 868 1071 reg = (opcode - pa->sym) / NBWLX; 869 } else if ( pa->instr_type & OPC_FARITH) {1072 } else if (OPCT_IS(pa->instr_type, OPC_FARITH)) { 870 1073 reg = (opcode - pa->sym) / 6; 871 1074 } else { 872 1075 reg = (pa->instr_type >> OPC_GROUP_SHIFT) & 7; 873 1076 } 1077 1078 pc = 0; 874 1079 if (pa->instr_type & OPC_MODRM) { 875 /* first look for an ea operand */876 for(i = 0;i < nb_ops; i++) {877 if (op_type[i] & OP_EA)878 goto modrm_found;879 }880 /* then if not found, a register or indirection (shift instructions) */881 for(i = 0;i < nb_ops; i++) {882 if (op_type[i] & (OP_REG | OP_MMX | OP_SSE | OP_INDIR))883 goto modrm_found;884 }885 #ifdef ASM_DEBUG886 tcc_error("bad op table");887 #endif888 modrm_found:889 modrm_index = i;890 1080 /* if a register is used in another operand then it is 891 1081 used instead of group */ 892 for(i = 0;i < nb_ops; i++) { 893 v = op_type[i]; 894 if (i != modrm_index && 895 (v & (OP_REG | OP_MMX | OP_SSE | OP_CR | OP_TR | OP_DB | OP_SEG))) { 896 reg = ops[i].reg; 897 break; 898 } 899 } 900 901 asm_modrm(reg, &ops[modrm_index]); 1082 if (modreg_index >= 0) 1083 reg = ops[modreg_index].reg; 1084 pc = asm_modrm(reg, &ops[modrm_index]); 902 1085 } 903 1086 904 1087 /* emit constants */ 905 1088 #ifndef TCC_TARGET_X86_64 906 if (pa->opcode == 0x9a || pa->opcode == 0xea) { 1089 if (!(pa->instr_type & OPC_0F) 1090 && (pa->opcode == 0x9a || pa->opcode == 0xea)) { 907 1091 /* ljmp or lcall kludge */ 908 #ifdef I386_ASM_16 909 if (s1->seg_size == 16 && o32 == 0) 910 gen_expr16(&ops[1].e); 911 else 912 #endif 913 gen_expr32(&ops[1].e); 1092 gen_expr32(&ops[1].e); 914 1093 if (ops[0].e.sym) 915 1094 tcc_error("cannot relocate"); … … 933 1112 v = OP_IM64; 934 1113 } 1114 1115 if ((v & (OP_IM8 | OP_IM8S | OP_IM16)) && ops[i].e.sym) 1116 tcc_error("cannot relocate"); 1117 935 1118 if (v & (OP_IM8 | OP_IM8S)) { 936 if (ops[i].e.sym)937 goto error_relocate;938 1119 g(ops[i].e.v); 939 1120 } else if (v & OP_IM16) { 940 #ifdef I386_ASM_16 941 if (s1->seg_size == 16) 942 gen_expr16(&ops[i].e); 943 else 944 #endif 945 if (ops[i].e.sym) 946 error_relocate: 947 tcc_error("cannot relocate"); 948 else 949 gen_le16(ops[i].e.v); 1121 gen_le16(ops[i].e.v); 1122 #ifdef TCC_TARGET_X86_64 1123 } else if (v & OP_IM64) { 1124 gen_expr64(&ops[i].e); 1125 #endif 1126 } else if (pa->op_type[i] == OPT_DISP || pa->op_type[i] == OPT_DISP8) { 1127 gen_disp32(&ops[i].e); 950 1128 } else { 951 if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) { 952 if (is_short_jmp) 953 g(ops[i].e.v); 954 #ifdef I386_ASM_16 955 else if (s1->seg_size == 16) 956 gen_disp16(&ops[i].e); 957 #endif 958 else 959 gen_disp32(&ops[i].e); 960 } else { 961 #ifdef I386_ASM_16 962 if (s1->seg_size == 16 && !((o32 == 1) && (v & OP_IM32))) 963 gen_expr16(&ops[i].e); 964 else 965 #endif 966 #ifdef TCC_TARGET_X86_64 967 if (v & OP_IM64) 968 gen_expr64(&ops[i].e); 969 else 970 #endif 971 gen_expr32(&ops[i].e); 972 } 1129 gen_expr32(&ops[i].e); 973 1130 } 974 #ifdef I386_ASM_16 975 } else if (v & (OP_REG16 | OP_REG32)) { 976 if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) { 977 /* jmp $r */ 978 g(0xE0 + ops[i].reg); 979 } 980 #endif 981 #ifdef TCC_TARGET_X86_64 982 } else if (v & (OP_REG32 | OP_REG64)) { 983 if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) { 984 /* jmp $r */ 985 g(0xE0 + ops[i].reg); 986 } 987 #endif 988 } 989 } 990 #ifdef I386_ASM_16 991 a32 = o32 = 0; 992 #endif 1131 } 1132 } 1133 1134 /* after immediate operands, adjust pc-relative address */ 1135 if (pc) 1136 add32le(cur_text_section->data + pc - 4, pc - ind); 993 1137 } 994 1138 … … 1022 1166 break; 1023 1167 case 'r': 1168 case 'R': 1169 case 'p': 1024 1170 pr = 3; 1025 1171 break; … … 1027 1173 case 'M': 1028 1174 case 'I': 1175 case 'e': 1029 1176 case 'i': 1030 1177 case 'm': … … 1047 1194 p++; 1048 1195 return p; 1196 } 1197 1198 /* If T (a token) is of the form "%reg" returns the register 1199 number and type, otherwise return -1. */ 1200 ST_FUNC int asm_parse_regvar (int t) 1201 { 1202 const char *s; 1203 Operand op; 1204 if (t < TOK_IDENT) 1205 return -1; 1206 s = table_ident[t - TOK_IDENT]->str; 1207 if (s[0] != '%') 1208 return -1; 1209 t = tok_alloc(s+1, strlen(s)-1)->tok; 1210 unget_tok(t); 1211 unget_tok('%'); 1212 parse_operand(tcc_state, &op); 1213 /* Accept only integer regs for now. */ 1214 if (op.type & OP_REG) 1215 return op.reg; 1216 else 1217 return -1; 1049 1218 } 1050 1219 … … 1091 1260 operands[k].input_index = i; 1092 1261 op->priority = 5; 1262 } else if ((op->vt->r & VT_VALMASK) == VT_LOCAL 1263 && op->vt->sym 1264 && (reg = op->vt->sym->r & VT_VALMASK) < VT_CONST) { 1265 op->priority = 1; 1266 op->reg = reg; 1093 1267 } else { 1094 1268 op->priority = constraint_priority(str); … … 1138 1312 reg_mask = REG_IN_MASK; 1139 1313 } 1314 if (op->reg >= 0) { 1315 if (is_reg_allocated(op->reg)) 1316 tcc_error("asm regvar requests register that's taken already"); 1317 reg = op->reg; 1318 goto reg_found; 1319 } 1140 1320 try_next: 1141 1321 c = *str++; … … 1190 1370 goto try_next; 1191 1371 case 'r': 1372 case 'R': 1373 case 'p': /* A general address, for x86(64) any register is acceptable*/ 1192 1374 /* any general register */ 1193 1375 for(reg = 0; reg < 8; reg++) { … … 1202 1384 regs_allocated[reg] |= reg_mask; 1203 1385 break; 1386 case 'e': 1204 1387 case 'i': 1205 1388 if (!((op->vt->r & (VT_VALMASK | VT_LVAL)) == VT_CONST)) … … 1294 1477 r = sv->r; 1295 1478 if ((r & VT_VALMASK) == VT_CONST) { 1296 if (!(r & VT_LVAL) && modifier != 'c' && modifier != 'n') 1479 if (!(r & VT_LVAL) && modifier != 'c' && modifier != 'n' && 1480 modifier != 'P') 1297 1481 cstr_ccat(add_str, '$'); 1298 1482 if (r & VT_SYM) { 1299 cstr_cat(add_str, get_tok_str(sv->sym->v, NULL)); 1300 if (sv->c.i != 0) { 1301 cstr_ccat(add_str, '+'); 1302 } else { 1303 return; 1304 } 1483 const char *name = get_tok_str(sv->sym->v, NULL); 1484 if (sv->sym->v >= SYM_FIRST_ANOM) { 1485 /* In case of anonymous symbols ("L.42", used 1486 for static data labels) we can't find them 1487 in the C symbol table when later looking up 1488 this name. So enter them now into the asm label 1489 list when we still know the symbol. */ 1490 get_asm_sym(tok_alloc(name, strlen(name))->tok, sv->sym); 1491 } 1492 cstr_cat(add_str, name, -1); 1493 if ((uint32_t)sv->c.i == 0) 1494 goto no_offset; 1495 cstr_ccat(add_str, '+'); 1305 1496 } 1306 1497 val = sv->c.i; 1307 1498 if (modifier == 'n') 1308 1499 val = -val; 1309 snprintf(buf, sizeof(buf), "%d", sv->c.i); 1310 cstr_cat(add_str, buf); 1500 snprintf(buf, sizeof(buf), "%d", (int)sv->c.i); 1501 cstr_cat(add_str, buf, -1); 1502 no_offset:; 1503 #ifdef TCC_TARGET_X86_64 1504 if (r & VT_LVAL) 1505 cstr_cat(add_str, "(%rip)", -1); 1506 #endif 1311 1507 } else if ((r & VT_VALMASK) == VT_LOCAL) { 1312 snprintf(buf, sizeof(buf), "%d(%%ebp)", sv->c.i); 1313 cstr_cat(add_str, buf); 1508 #ifdef TCC_TARGET_X86_64 1509 snprintf(buf, sizeof(buf), "%d(%%rbp)", (int)sv->c.i); 1510 #else 1511 snprintf(buf, sizeof(buf), "%d(%%ebp)", (int)sv->c.i); 1512 #endif 1513 cstr_cat(add_str, buf, -1); 1314 1514 } else if (r & VT_LVAL) { 1315 1515 reg = r & VT_VALMASK; … … 1317 1517 tcc_error("internal compiler error"); 1318 1518 snprintf(buf, sizeof(buf), "(%%%s)", 1319 get_tok_str(TOK_ASM_eax + reg, NULL)); 1320 cstr_cat(add_str, buf); 1519 #ifdef TCC_TARGET_X86_64 1520 get_tok_str(TOK_ASM_rax + reg, NULL) 1521 #else 1522 get_tok_str(TOK_ASM_eax + reg, NULL) 1523 #endif 1524 ); 1525 cstr_cat(add_str, buf, -1); 1321 1526 } else { 1322 1527 /* register case */ … … 1326 1531 1327 1532 /* choose register operand size */ 1328 if ((sv->type.t & VT_BTYPE) == VT_BYTE) 1533 if ((sv->type.t & VT_BTYPE) == VT_BYTE || 1534 (sv->type.t & VT_BTYPE) == VT_BOOL) 1329 1535 size = 1; 1330 1536 else if ((sv->type.t & VT_BTYPE) == VT_SHORT) 1331 1537 size = 2; 1332 1538 #ifdef TCC_TARGET_X86_64 1333 else if ((sv->type.t & VT_BTYPE) == VT_LLONG) 1539 else if ((sv->type.t & VT_BTYPE) == VT_LLONG || 1540 (sv->type.t & VT_BTYPE) == VT_PTR) 1334 1541 size = 8; 1335 1542 #endif … … 1349 1556 } else if (modifier == 'w') { 1350 1557 size = 2; 1558 } else if (modifier == 'k') { 1559 size = 4; 1351 1560 #ifdef TCC_TARGET_X86_64 1352 1561 } else if (modifier == 'q') { … … 1375 1584 } 1376 1585 snprintf(buf, sizeof(buf), "%%%s", get_tok_str(reg, NULL)); 1377 cstr_cat(add_str, buf );1586 cstr_cat(add_str, buf, -1); 1378 1587 } 1379 1588 } 1380 1589 1381 /* generate prolog and epilog code for asm stat ment */1590 /* generate prolog and epilog code for asm statement */ 1382 1591 ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, 1383 1592 int nb_outputs, int is_output, … … 1388 1597 ASMOperand *op; 1389 1598 int i, reg; 1390 static uint8_t reg_saved[NB_SAVED_REGS] = { 3, 6, 7 }; 1599 1600 /* Strictly speaking %Xbp and %Xsp should be included in the 1601 call-preserved registers, but currently it doesn't matter. */ 1602 #ifdef TCC_TARGET_X86_64 1603 #ifdef TCC_TARGET_PE 1604 static uint8_t reg_saved[] = { 3, 6, 7, 12, 13, 14, 15 }; 1605 #else 1606 static uint8_t reg_saved[] = { 3, 12, 13, 14, 15 }; 1607 #endif 1608 #else 1609 static uint8_t reg_saved[] = { 3, 6, 7 }; 1610 #endif 1391 1611 1392 1612 /* mark all used registers */ … … 1399 1619 if (!is_output) { 1400 1620 /* generate reg save code */ 1401 for(i = 0; i < NB_SAVED_REGS; i++) {1621 for(i = 0; i < sizeof(reg_saved)/sizeof(reg_saved[0]); i++) { 1402 1622 reg = reg_saved[i]; 1403 1623 if (regs_allocated[reg]) { 1404 #ifdef I386_ASM_16 1405 if (tcc_state->seg_size == 16) 1406 g(0x66); 1407 #endif 1624 if (reg >= 8) 1625 g(0x41), reg-=8; 1408 1626 g(0x50 + reg); 1409 1627 } … … 1420 1638 SValue sv; 1421 1639 sv = *op->vt; 1422 sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL; 1640 sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL | VT_LVAL; 1641 sv.type.t = VT_PTR; 1423 1642 load(op->reg, &sv); 1424 1643 } else if (i >= nb_outputs || op->is_rw) { … … 1428 1647 SValue sv; 1429 1648 sv = *op->vt; 1430 sv.c. ul+= 4;1649 sv.c.i += 4; 1431 1650 load(TREG_XDX, &sv); 1432 1651 } … … 1444 1663 sv = *op->vt; 1445 1664 sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL; 1665 sv.type.t = VT_PTR; 1446 1666 load(out_reg, &sv); 1447 1667 1668 sv = *op->vt; 1448 1669 sv.r = (sv.r & ~VT_VALMASK) | out_reg; 1449 1670 store(op->reg, &sv); … … 1454 1675 SValue sv; 1455 1676 sv = *op->vt; 1456 sv.c. ul+= 4;1677 sv.c.i += 4; 1457 1678 store(TREG_XDX, &sv); 1458 1679 } … … 1461 1682 } 1462 1683 /* generate reg restore code */ 1463 for(i = NB_SAVED_REGS- 1; i >= 0; i--) {1684 for(i = sizeof(reg_saved)/sizeof(reg_saved[0]) - 1; i >= 0; i--) { 1464 1685 reg = reg_saved[i]; 1465 1686 if (regs_allocated[reg]) { 1466 #ifdef I386_ASM_16 1467 if (tcc_state->seg_size == 16) 1468 g(0x66); 1469 #endif 1687 if (reg >= 8) 1688 g(0x41), reg-=8; 1470 1689 g(0x58 + reg); 1471 1690 } … … 1478 1697 int reg; 1479 1698 TokenSym *ts; 1699 #ifdef TCC_TARGET_X86_64 1700 unsigned int type; 1701 #endif 1480 1702 1481 1703 if (!strcmp(str, "memory") || 1482 !strcmp(str, "cc")) 1704 !strcmp(str, "cc") || 1705 !strcmp(str, "flags")) 1483 1706 return; 1484 1707 ts = tok_alloc(str, strlen(str)); … … 1491 1714 } else if (reg >= TOK_ASM_rax && reg <= TOK_ASM_rdi) { 1492 1715 reg -= TOK_ASM_rax; 1716 } else if ((reg = asm_parse_numeric_reg(reg, &type)) >= 0) { 1717 ; 1493 1718 #endif 1494 1719 } else {
Note:
See TracChangeset
for help on using the changeset viewer.