浏览代码

x86 assembler improvements:
* Don't generate rex.w for "CALL|JMP|LCALL|LJMP regmem", they are 64-bit by default.
* LCALL,LJMP flagged as calljump instructions.
* LCALL,LJMP encode only far jumps and don't accept register operands.
* GAS writer: fixed writing rip-relative operands of calljump instructions.
+ test.

git-svn-id: trunk@19413 -

sergei 14 年之前
父节点
当前提交
e11c880b1e
共有 6 个文件被更改,包括 103 次插入69 次删除
  1. 30 30
      compiler/i386/i386tab.inc
  2. 1 1
      compiler/x86/agx86att.pas
  3. 2 0
      compiler/x86/cpubase.pas
  4. 17 8
      compiler/x86/x86ins.dat
  5. 30 30
      compiler/x86_64/x8664tab.inc
  6. 23 0
      tests/test/tasm2.pp

+ 30 - 30
compiler/i386/i386tab.inc

@@ -381,15 +381,22 @@
   (
     opcode  : A_CALL;
     ops     : 1;
-    optypes : (ot_immediate,ot_none,ot_none,ot_none);
-    code    : #208#1#232#52;
+    optypes : (ot_rm_gpr or ot_bits32,ot_none,ot_none,ot_none);
+    code    : #213#1#255#130;
+    flags   : if_386 or if_nox86_64
+  ),
+  (
+    opcode  : A_CALL;
+    ops     : 1;
+    optypes : (ot_rm_gpr or ot_bits16,ot_none,ot_none,ot_none);
+    code    : #212#1#255#130;
     flags   : if_8086
   ),
   (
     opcode  : A_CALL;
     ops     : 1;
-    optypes : (ot_rm_gpr or ot_bits16 or ot_bits32 or ot_bits64,ot_none,ot_none,ot_none);
-    code    : #208#1#255#130;
+    optypes : (ot_immediate,ot_none,ot_none,ot_none);
+    code    : #208#1#232#52;
     flags   : if_8086
   ),
   (
@@ -2537,8 +2544,15 @@
   (
     opcode  : A_JMP;
     ops     : 1;
-    optypes : (ot_rm_gpr or ot_bits16 or ot_bits32 or ot_bits64,ot_none,ot_none,ot_none);
-    code    : #208#1#255#132;
+    optypes : (ot_rm_gpr or ot_bits32,ot_none,ot_none,ot_none);
+    code    : #213#1#255#132;
+    flags   : if_386 or if_nox86_64
+  ),
+  (
+    opcode  : A_JMP;
+    ops     : 1;
+    optypes : (ot_rm_gpr or ot_bits16,ot_none,ot_none,ot_none);
+    code    : #212#1#255#132;
     flags   : if_8086
   ),
   (
@@ -2614,22 +2628,15 @@
   (
     opcode  : A_LCALL;
     ops     : 1;
-    optypes : (ot_rm_gpr or ot_bits16 or ot_bits32 or ot_bits64,ot_none,ot_none,ot_none);
-    code    : #208#1#255#130;
-    flags   : if_8086
-  ),
-  (
-    opcode  : A_LCALL;
-    ops     : 1;
-    optypes : (ot_memory or ot_near,ot_none,ot_none,ot_none);
-    code    : #208#1#255#130;
-    flags   : if_8086
+    optypes : (ot_memory or ot_bits32,ot_none,ot_none,ot_none);
+    code    : #213#1#255#131;
+    flags   : if_386 or if_nox86_64
   ),
   (
     opcode  : A_LCALL;
     ops     : 1;
-    optypes : (ot_memory or ot_far,ot_none,ot_none,ot_none);
-    code    : #208#1#255#131;
+    optypes : (ot_memory or ot_bits16,ot_none,ot_none,ot_none);
+    code    : #212#1#255#131;
     flags   : if_8086
   ),
   (
@@ -2698,22 +2705,15 @@
   (
     opcode  : A_LJMP;
     ops     : 1;
-    optypes : (ot_rm_gpr or ot_bits16 or ot_bits32 or ot_bits64,ot_none,ot_none,ot_none);
-    code    : #208#1#255#133;
-    flags   : if_8086
-  ),
-  (
-    opcode  : A_LJMP;
-    ops     : 1;
-    optypes : (ot_memory or ot_far,ot_none,ot_none,ot_none);
-    code    : #208#1#255#133;
-    flags   : if_8086
+    optypes : (ot_memory or ot_bits32,ot_none,ot_none,ot_none);
+    code    : #213#1#255#133;
+    flags   : if_386 or if_nox86_64
   ),
   (
     opcode  : A_LJMP;
     ops     : 1;
-    optypes : (ot_memory or ot_near,ot_none,ot_none,ot_none);
-    code    : #208#1#255#132;
+    optypes : (ot_memory or ot_bits16,ot_none,ot_none,ot_none);
+    code    : #212#1#255#133;
     flags   : if_8086
   ),
   (

+ 1 - 1
compiler/x86/agx86att.pas

@@ -201,7 +201,7 @@ interface
             owner.AsmWrite('*'+gas_regname(o.reg));
           top_ref :
             begin
-              if o.ref^.refaddr=addr_no then
+              if o.ref^.refaddr in [addr_no,addr_pic_no_got] then
                 begin
                   owner.AsmWrite('*');
                   WriteReference(o.ref^);

+ 2 - 0
compiler/x86/cpubase.pas

@@ -407,6 +407,8 @@ implementation
           A_LOOPNE,
           A_LOOPNZ,
           A_LOOPZ,
+          A_LCALL,
+          A_LJMP,
           A_Jcc :
             is_calljmp:=true;
           else

+ 17 - 8
compiler/x86/x86ins.dat

@@ -124,8 +124,13 @@ rm16|32|64,imm        \320\2\x0F\xBA\205\25           386,SB
 [CALL,call]
 ; don't know value of any register
 (Ch_ROp1, Ch_All, Ch_None)
+; Compiler emits CALL/JMP with opsize=S_NO which matches any size,
+; and will match the first entry in sequence.
+; Therefore rm16 must be placed after rm32/rm64
+rm32                  \325\1\xFF\202                  386,NOX86_64
+rm64                  \335\1\xFF\202                  X86_64
+rm16                  \324\1\xFF\202                  8086
 imm                   \320\1\xE8\64                   8086
-rm16|32|64            \320\1\xFF\202                  8086
 imm|near              \320\1\xE8\64                   8086
 imm|far               \320\1\x9A\34\37                8086,ND,NOX86_64
 mem|near              \320\1\xFF\202                  8086
@@ -880,9 +885,12 @@ imm                   \1\xE3\50                       X86_64
 
 [JMP,jmpX]
 (Ch_ROp1, Ch_None, Ch_None)
+; rm16 should be after rm32/rm64, see comments for CALL.
 imm8                  \1\xEB\50                       8086,PASS2
 imm16|32              \320\1\xE9\64                   8086,PASS2
-rm16|32|64            \320\1\xFF\204                  8086
+rm32                  \325\1\xFF\204                  386,NOX86_64
+rm64                  \335\1\xFF\204                  X86_64
+rm16                  \324\1\xFF\204                  8086
 imm|short             \1\xEB\50                       8086,PASS2
 imm|near              \320\1\xE9\64                   8086,ND,PASS2
 imm|far               \320\1\xEA\34\37                8086,ND,PASS2,NOX86_64
@@ -903,10 +911,11 @@ reg16|32|64,regmem    \320\2\x0F\x02\110              286,PROT,SM
 
 [LCALL,lcall]
 ; don't know value of any register
+; Far call, AT&T only (there are no near/far modifiers in AT&T syntax, so separate mnemonic is needed)
 (Ch_All, Ch_None, Ch_None)
-rm16|32|64            \320\1\xFF\202                  8086
-mem|near              \320\1\xFF\202                  8086
-mem|far               \320\1\xFF\203                  8086
+mem32                  \325\1\xFF\203                  386,NOX86_64
+mem64                  \335\1\xFF\203                  X86_64
+mem16                  \324\1\xFF\203                  8086
 
 [LDS,ldsX]
 (Ch_Wop2, Ch_Rop1, Ch_None)
@@ -943,9 +952,9 @@ mem                   \2\x0F\x01\203                  286,PRIV
 
 [LJMP,ljmp]
 (Ch_ROp1, Ch_None, Ch_None)
-rm16|32|64            \320\1\xFF\205                  8086
-mem|far               \320\1\xFF\205                  8086
-mem|near              \320\1\xFF\204                  8086
+mem32                 \325\1\xFF\205                  386,NOX86_64
+mem64                 \335\1\xFF\205                  X86_64
+mem16                 \324\1\xFF\205                  8086
 
 [LLDT,lldtX]
 (Ch_None, Ch_None, Ch_None)

+ 30 - 30
compiler/x86_64/x8664tab.inc

@@ -360,15 +360,22 @@
   (
     opcode  : A_CALL;
     ops     : 1;
-    optypes : (ot_immediate,ot_none,ot_none,ot_none);
-    code    : #208#1#232#52;
+    optypes : (ot_rm_gpr or ot_bits64,ot_none,ot_none,ot_none);
+    code    : #221#1#255#130;
+    flags   : if_x86_64
+  ),
+  (
+    opcode  : A_CALL;
+    ops     : 1;
+    optypes : (ot_rm_gpr or ot_bits16,ot_none,ot_none,ot_none);
+    code    : #212#1#255#130;
     flags   : if_8086
   ),
   (
     opcode  : A_CALL;
     ops     : 1;
-    optypes : (ot_rm_gpr or ot_bits16 or ot_bits32 or ot_bits64,ot_none,ot_none,ot_none);
-    code    : #208#1#255#130;
+    optypes : (ot_immediate,ot_none,ot_none,ot_none);
+    code    : #208#1#232#52;
     flags   : if_8086
   ),
   (
@@ -2467,8 +2474,15 @@
   (
     opcode  : A_JMP;
     ops     : 1;
-    optypes : (ot_rm_gpr or ot_bits16 or ot_bits32 or ot_bits64,ot_none,ot_none,ot_none);
-    code    : #208#1#255#132;
+    optypes : (ot_rm_gpr or ot_bits64,ot_none,ot_none,ot_none);
+    code    : #221#1#255#132;
+    flags   : if_x86_64
+  ),
+  (
+    opcode  : A_JMP;
+    ops     : 1;
+    optypes : (ot_rm_gpr or ot_bits16,ot_none,ot_none,ot_none);
+    code    : #212#1#255#132;
     flags   : if_8086
   ),
   (
@@ -2516,22 +2530,15 @@
   (
     opcode  : A_LCALL;
     ops     : 1;
-    optypes : (ot_rm_gpr or ot_bits16 or ot_bits32 or ot_bits64,ot_none,ot_none,ot_none);
-    code    : #208#1#255#130;
-    flags   : if_8086
-  ),
-  (
-    opcode  : A_LCALL;
-    ops     : 1;
-    optypes : (ot_memory or ot_near,ot_none,ot_none,ot_none);
-    code    : #208#1#255#130;
-    flags   : if_8086
+    optypes : (ot_memory or ot_bits64,ot_none,ot_none,ot_none);
+    code    : #221#1#255#131;
+    flags   : if_x86_64
   ),
   (
     opcode  : A_LCALL;
     ops     : 1;
-    optypes : (ot_memory or ot_far,ot_none,ot_none,ot_none);
-    code    : #208#1#255#131;
+    optypes : (ot_memory or ot_bits16,ot_none,ot_none,ot_none);
+    code    : #212#1#255#131;
     flags   : if_8086
   ),
   (
@@ -2586,22 +2593,15 @@
   (
     opcode  : A_LJMP;
     ops     : 1;
-    optypes : (ot_rm_gpr or ot_bits16 or ot_bits32 or ot_bits64,ot_none,ot_none,ot_none);
-    code    : #208#1#255#133;
-    flags   : if_8086
-  ),
-  (
-    opcode  : A_LJMP;
-    ops     : 1;
-    optypes : (ot_memory or ot_far,ot_none,ot_none,ot_none);
-    code    : #208#1#255#133;
-    flags   : if_8086
+    optypes : (ot_memory or ot_bits64,ot_none,ot_none,ot_none);
+    code    : #221#1#255#133;
+    flags   : if_x86_64
   ),
   (
     opcode  : A_LJMP;
     ops     : 1;
-    optypes : (ot_memory or ot_near,ot_none,ot_none,ot_none);
-    code    : #208#1#255#132;
+    optypes : (ot_memory or ot_bits16,ot_none,ot_none,ot_none);
+    code    : #212#1#255#133;
     flags   : if_8086
   ),
   (

+ 23 - 0
tests/test/tasm2.pp

@@ -195,6 +195,18 @@ asm
 //    movsd     %xmm8,(%rax)
 end;
 
+procedure tcalljump; assembler; nostackframe;
+asm
+    call   *0x12345678(%rip)
+    call   *(%rax)
+    jmp    *0x12345678(%rip)
+    jmp    *(%rax)
+    lcall  *0x12345678(%rip)
+    lcall  *(%rax)
+    ljmp   *0x12345678(%rip)
+    ljmp   *(%rax)
+end;
+
 const
   test_expected : array[0..745] of byte = (
     $66,$44,$0F,$D0,$05,$78,$56,$34,
@@ -273,6 +285,16 @@ const
     $0F,$7E,$C0
   );
 
+  tcalljump_expected: array[0..31] of byte = (
+    $ff,$15,$78,$56,$34,$12,
+    $ff,$10,
+    $ff,$25,$78,$56,$34,$12,
+    $ff,$20,
+    $ff,$1d,$78,$56,$34,$12,
+    $ff,$18,
+    $ff,$2d,$78,$56,$34,$12,
+    $ff,$28
+  );
 
 procedure check(const id: string; const expected: array of byte; p: pointer);
 var
@@ -290,5 +312,6 @@ begin
   check('generic', test_expected, @test);
   check('movq', tmovq_expected, @tmovq);
   check('movd', tmovd_expected, @tmovd);
+  check('calljmp', tcalljump_expected, @tcalljump);
   writeln('ok');
 end.